{"model_name":"gpt-5.4-high","codes":{"1":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int BOARD = 10000;\nstatic constexpr long double INF_CAP = 1e18L;\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n    int area() const { return (r - l) * (t - b); }\n};\n\nenum Action {\n    EXP_L = 0,\n    EXP_R = 1,\n    EXP_B = 2,\n    EXP_T = 3,\n    SHR_L = 4,\n    SHR_R = 5,\n    SHR_B = 6,\n    SHR_T = 7\n};\n\nstruct Move {\n    bool valid = false;\n    int action = 0;\n    int delta = 0;\n    int freecap = 0;\n    int prio = 0;\n    long double gain = 0;\n    long double sec = 0;\n};\n\nstruct Params {\n    vector<long double> caps;\n    int order_mode = 0;\n    bool reverse_axis = false;\n    array<int, 8> action_prio{};\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int mod) {\n        return (int)(next_u64() % (uint64_t)mod);\n    }\n    long double uniform() {\n        return (next_u64() >> 11) * (1.0L / (1ULL << 53));\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n};\n\nstruct Solver {\n    int n;\n    vector<int> xs, ys, rs;\n    vector<long double> sqrs;\n    vector<int> nearest_idx;\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    static bool overlap1d(int l1, int r1, int l2, int r2) {\n        return max(l1, l2) < min(r1, r2);\n    }\n\n    long double sat(int need, int area) const {\n        if (area <= 0) return 0;\n        long double t = (long double)min(need, area) / (long double)max(need, area);\n        long double u = 1.0L - t;\n        return 1.0L - u * u;\n    }\n\n    long double total_score(const vector<Rect>& rects) const {\n        long double res = 0;\n        for (int i = 0; i < n; ++i) res += sat(rs[i], rects[i].area());\n        return res;\n    }\n\n    vector<Rect> initial_rects() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; ++i) rects[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n        return rects;\n    }\n\n    void apply_move(Rect& rc, int action, int delta) const {\n        switch (action) {\n            case EXP_L: rc.l -= delta; break;\n            case EXP_R: rc.r += delta; break;\n            case EXP_B: rc.b -= delta; break;\n            case EXP_T: rc.t += delta; break;\n            case SHR_L: rc.l += delta; break;\n            case SHR_R: rc.r -= delta; break;\n            case SHR_B: rc.b += delta; break;\n            case SHR_T: rc.t -= delta; break;\n        }\n    }\n\n    bool better_move(const Move& a, const Move& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const long double EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        if (a.delta < b.delta) return true;\n        if (a.delta > b.delta) return false;\n        if (a.freecap > b.freecap) return true;\n        if (a.freecap < b.freecap) return false;\n        return a.prio < b.prio;\n    }\n\n    void compute_expand_limits(int i, const vector<Rect>& rects,\n                               int& maxL, int& maxR, int& maxB, int& maxT) const {\n        const Rect& a = rects[i];\n        int limL = 0, limR = BOARD, limB = 0, limT = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& o = rects[j];\n            if (overlap1d(a.b, a.t, o.b, o.t)) {\n                if (o.r <= a.l) limL = max(limL, o.r);\n                if (o.l >= a.r) limR = min(limR, o.l);\n            }\n            if (overlap1d(a.l, a.r, o.l, o.r)) {\n                if (o.t <= a.b) limB = max(limB, o.t);\n                if (o.b >= a.t) limT = min(limT, o.b);\n            }\n        }\n        maxL = a.l - limL;\n        maxR = limR - a.r;\n        maxB = a.b - limB;\n        maxT = limT - a.t;\n    }\n\n    static void add_expand_targets(vector<int>& v, long double target, int cur) {\n        long double eps = 1e-12L;\n        int f = (int)floor(target + eps);\n        int c = (int)ceil(target - eps);\n        if (f > cur) v.push_back(f);\n        if (c > cur) v.push_back(c);\n    }\n\n    static void add_shrink_targets(vector<int>& v, long double target, int cur) {\n        long double eps = 1e-12L;\n        int f = (int)floor(target + eps);\n        int c = (int)ceil(target - eps);\n        if (f >= 1 && f < cur) v.push_back(f);\n        if (c >= 1 && c < cur) v.push_back(c);\n    }\n\n    Move best_move_for_rect(int i, const vector<Rect>& rects,\n                            long double shape_cap, bool aggressive,\n                            const array<int, 8>& prio_map) const {\n        const Rect& cur = rects[i];\n        int w = cur.r - cur.l;\n        int h = cur.t - cur.b;\n        int area = w * h;\n        int need = rs[i];\n        long double cur_sat = sat(need, area);\n\n        int maxL, maxR, maxB, maxT;\n        compute_expand_limits(i, rects, maxL, maxR, maxB, maxT);\n\n        int marginL = xs[i] - cur.l;\n        int marginR = cur.r - (xs[i] + 1);\n        int marginB = ys[i] - cur.b;\n        int marginT = cur.t - (ys[i] + 1);\n\n        vector<Move> cands;\n\n        auto push_candidate = [&](int action, int delta, int freecap) {\n            if (delta <= 0) return;\n            for (const auto& mv : cands) {\n                if (mv.action == action && mv.delta == delta) return;\n            }\n            Rect nr = cur;\n            apply_move(nr, action, delta);\n\n            int nw = nr.r - nr.l;\n            int nh = nr.t - nr.b;\n            int ns = nw * nh;\n            long double g = sat(need, ns) - cur_sat;\n            if (g <= 1e-18L) return;\n\n            int nL = xs[i] - nr.l;\n            int nR = nr.r - (xs[i] + 1);\n            int nB = ys[i] - nr.b;\n            int nT = nr.t - (ys[i] + 1);\n\n            long double aspect = (long double)max(nw, nh) / (long double)min(nw, nh);\n            long double imbalance = (long double)(abs(nL - nR) + abs(nB - nT)) / (long double)(nw + nh);\n            long double sec = aspect + 0.25L * imbalance;\n\n            Move mv;\n            mv.valid = true;\n            mv.action = action;\n            mv.delta = delta;\n            mv.freecap = freecap;\n            mv.prio = prio_map[action];\n            mv.gain = g;\n            mv.sec = sec;\n            cands.push_back(mv);\n        };\n\n        if (area < need) {\n            long double exactW = (long double)need / (long double)h;\n            long double exactH = (long double)need / (long double)w;\n\n            // Horizontal expansion\n            vector<int> wTargets;\n            add_expand_targets(wTargets, min(exactW, sqrs[i] * shape_cap), w);\n            if (aggressive) add_expand_targets(wTargets, exactW, w);\n            sort(wTargets.begin(), wTargets.end());\n            wTargets.erase(unique(wTargets.begin(), wTargets.end()), wTargets.end());\n\n            bool centered_horizontal_added = false;\n            for (int Wtar : wTargets) {\n                int totalMargins = Wtar - 1;\n                int targetL = totalMargins / 2;\n                int targetR = totalMargins - targetL;\n\n                int dL = targetL - marginL;\n                if (dL > 0 && maxL > 0) {\n                    push_candidate(EXP_L, min(dL, maxL), maxL);\n                    centered_horizontal_added = true;\n                }\n                int dR = targetR - marginR;\n                if (dR > 0 && maxR > 0) {\n                    push_candidate(EXP_R, min(dR, maxR), maxR);\n                    centered_horizontal_added = true;\n                }\n            }\n            if (aggressive && !centered_horizontal_added) {\n                vector<int> exTargets;\n                add_expand_targets(exTargets, exactW, w);\n                sort(exTargets.begin(), exTargets.end());\n                exTargets.erase(unique(exTargets.begin(), exTargets.end()), exTargets.end());\n                for (int Wtar : exTargets) {\n                    int d = Wtar - w;\n                    if (d > 0) {\n                        if (maxL > 0) push_candidate(EXP_L, min(d, maxL), maxL);\n                        if (maxR > 0) push_candidate(EXP_R, min(d, maxR), maxR);\n                    }\n                }\n            }\n\n            // Vertical expansion\n            vector<int> hTargets;\n            add_expand_targets(hTargets, min(exactH, sqrs[i] * shape_cap), h);\n            if (aggressive) add_expand_targets(hTargets, exactH, h);\n            sort(hTargets.begin(), hTargets.end());\n            hTargets.erase(unique(hTargets.begin(), hTargets.end()), hTargets.end());\n\n            bool centered_vertical_added = false;\n            for (int Htar : hTargets) {\n                int totalMargins = Htar - 1;\n                int targetB = totalMargins / 2;\n                int targetT = totalMargins - targetB;\n\n                int dB = targetB - marginB;\n                if (dB > 0 && maxB > 0) {\n                    push_candidate(EXP_B, min(dB, maxB), maxB);\n                    centered_vertical_added = true;\n                }\n                int dT = targetT - marginT;\n                if (dT > 0 && maxT > 0) {\n                    push_candidate(EXP_T, min(dT, maxT), maxT);\n                    centered_vertical_added = true;\n                }\n            }\n            if (aggressive && !centered_vertical_added) {\n                vector<int> exTargets;\n                add_expand_targets(exTargets, exactH, h);\n                sort(exTargets.begin(), exTargets.end());\n                exTargets.erase(unique(exTargets.begin(), exTargets.end()), exTargets.end());\n                for (int Htar : exTargets) {\n                    int d = Htar - h;\n                    if (d > 0) {\n                        if (maxB > 0) push_candidate(EXP_B, min(d, maxB), maxB);\n                        if (maxT > 0) push_candidate(EXP_T, min(d, maxT), maxT);\n                    }\n                }\n            }\n        } else if (area > need) {\n            long double exactW = (long double)need / (long double)h;\n            long double exactH = (long double)need / (long double)w;\n\n            // Horizontal shrink\n            vector<int> wTargets;\n            add_shrink_targets(wTargets, exactW, w);\n            sort(wTargets.begin(), wTargets.end());\n            wTargets.erase(unique(wTargets.begin(), wTargets.end()), wTargets.end());\n            for (int Wtar : wTargets) {\n                int totalMargins = Wtar - 1;\n                int targetL = totalMargins / 2;\n                int targetR = totalMargins - targetL;\n\n                int dL = marginL - targetL;\n                if (dL > 0) push_candidate(SHR_L, min(dL, marginL), marginL);\n\n                int dR = marginR - targetR;\n                if (dR > 0) push_candidate(SHR_R, min(dR, marginR), marginR);\n            }\n\n            // Vertical shrink\n            vector<int> hTargets;\n            add_shrink_targets(hTargets, exactH, h);\n            sort(hTargets.begin(), hTargets.end());\n            hTargets.erase(unique(hTargets.begin(), hTargets.end()), hTargets.end());\n            for (int Htar : hTargets) {\n                int totalMargins = Htar - 1;\n                int targetB = totalMargins / 2;\n                int targetT = totalMargins - targetB;\n\n                int dB = marginB - targetB;\n                if (dB > 0) push_candidate(SHR_B, min(dB, marginB), marginB);\n\n                int dT = marginT - targetT;\n                if (dT > 0) push_candidate(SHR_T, min(dT, marginT), marginT);\n            }\n        }\n\n        Move best;\n        for (const auto& mv : cands) {\n            if (better_move(mv, best)) best = mv;\n        }\n        return best;\n    }\n\n    vector<int> build_order(const vector<Rect>& rects, int mode, bool reverse_axis) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n\n        if (mode == 0) return ord;\n\n        if (mode == 1) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return rs[a] > rs[b];\n            });\n        } else if (mode == 2) {\n            vector<long double> key(n);\n            for (int i = 0; i < n; ++i) key[i] = 1.0L - sat(rs[i], rects[i].area());\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        } else if (mode == 3) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] < xs[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] > xs[b];\n                });\n            }\n        } else if (mode == 4) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] < ys[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] > ys[b];\n                });\n            }\n        } else if (mode == 5) {\n            vector<int> key(n);\n            for (int i = 0; i < n; ++i) key[i] = rs[i] - rects[i].area();\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        }\n\n        return ord;\n    }\n\n    long double optimize(vector<Rect>& rects, const Params& params) {\n        for (int pass = 0; pass < (int)params.caps.size(); ++pass) {\n            long double cap = params.caps[pass];\n            bool aggressive = (cap > 1e9L);\n            int mode = aggressive ? ((pass & 1) ? 5 : 2) : params.order_mode;\n            vector<int> ord = build_order(rects, mode, params.reverse_axis);\n\n            bool any = false;\n            for (int idx : ord) {\n                Move mv = best_move_for_rect(idx, rects, cap, aggressive, params.action_prio);\n                if (mv.valid) {\n                    apply_move(rects[idx], mv.action, mv.delta);\n                    any = true;\n                }\n            }\n            if (!any && aggressive) break;\n        }\n\n        // Final polish\n        for (int rep = 0; rep < 3; ++rep) {\n            bool any = false;\n            int mode = (rep & 1) ? 5 : 2;\n            vector<int> ord = build_order(rects, mode, false);\n            for (int idx : ord) {\n                Move mv = best_move_for_rect(idx, rects, INF_CAP, true, params.action_prio);\n                if (mv.valid) {\n                    apply_move(rects[idx], mv.action, mv.delta);\n                    any = true;\n                }\n            }\n            if (!any) break;\n        }\n\n        return total_score(rects);\n    }\n\n    array<int, 8> random_action_priority() {\n        vector<int> ord(8);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n        array<int, 8> pr{};\n        for (int i = 0; i < 8; ++i) pr[ord[i]] = i;\n        return pr;\n    }\n\n    Params random_constructive_params() {\n        Params p;\n        long double c0 = 0.85L + 0.45L * rng.uniform();\n        p.caps = {c0, c0, c0 * 1.35L, c0 * 1.35L, c0 * 1.8L, c0 * 2.5L, INF_CAP, INF_CAP};\n\n        long double u = rng.uniform();\n        if (u < 0.25L) p.order_mode = 0;\n        else if (u < 0.45L) p.order_mode = 1;\n        else if (u < 0.68L) p.order_mode = 2;\n        else if (u < 0.83L) p.order_mode = 5;\n        else if (u < 0.915L) p.order_mode = 3;\n        else p.order_mode = 4;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_perturb_params() {\n        Params p;\n        long double c0 = 0.95L + 0.55L * rng.uniform();\n        p.caps = {c0, c0 * 1.5L, c0 * 2.2L, INF_CAP, INF_CAP};\n\n        long double u = rng.uniform();\n        if (u < 0.45L) p.order_mode = 2;\n        else if (u < 0.75L) p.order_mode = 5;\n        else if (u < 0.90L) p.order_mode = 0;\n        else p.order_mode = 1;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    int weighted_pick(const vector<long double>& w, const vector<char>& banned) {\n        long double sum = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) sum += w[i];\n        if (sum <= 0) {\n            vector<int> cand;\n            for (int i = 0; i < n; ++i) if (!banned[i]) cand.push_back(i);\n            if (cand.empty()) return -1;\n            return cand[rng.next_int((int)cand.size())];\n        }\n        long double z = rng.uniform() * sum;\n        long double acc = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) {\n            acc += w[i];\n            if (acc >= z) return i;\n        }\n        for (int i = n - 1; i >= 0; --i) if (!banned[i]) return i;\n        return -1;\n    }\n\n    vector<Rect> perturb_from_best(const vector<Rect>& best) {\n        vector<Rect> seed = best;\n        vector<long double> w(n);\n        for (int i = 0; i < n; ++i) {\n            w[i] = 0.01L + (1.0L - sat(rs[i], best[i].area()));\n        }\n        vector<char> banned(n, 0);\n        int k = 1 + rng.next_int(min(3, n));\n\n        auto reset_rect = [&](int idx) {\n            if (idx < 0) return;\n            seed[idx] = {xs[idx], ys[idx], xs[idx] + 1, ys[idx] + 1};\n            banned[idx] = 1;\n        };\n\n        for (int it = 0; it < k; ++it) {\n            int idx = weighted_pick(w, banned);\n            if (idx < 0) break;\n            reset_rect(idx);\n            if (nearest_idx[idx] != -1 && rng.next_int(100) < 50) {\n                reset_rect(nearest_idx[idx]);\n            }\n        }\n        return seed;\n    }\n\n    long double elapsed_sec() const {\n        return chrono::duration<long double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        xs.resize(n);\n        ys.resize(n);\n        rs.resize(n);\n        sqrs.resize(n);\n\n        uint64_t seed = 1469598103934665603ULL;\n        for (int i = 0; i < n; ++i) {\n            cin >> xs[i] >> ys[i] >> rs[i];\n            sqrs[i] = sqrt((long double)rs[i]);\n            seed ^= (uint64_t)(xs[i] + 1) * 1000003ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(ys[i] + 7) * 1000033ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(rs[i] + 13) * 1000037ULL;\n            seed *= 1099511628211ULL;\n        }\n        rng = XorShift64(seed);\n\n        nearest_idx.assign(n, -1);\n        for (int i = 0; i < n; ++i) {\n            long long bestd = (1LL << 62);\n            for (int j = 0; j < n; ++j) if (i != j) {\n                long long dx = xs[i] - xs[j];\n                long long dy = ys[i] - ys[j];\n                long long d = dx * dx + dy * dy;\n                if (d < bestd) {\n                    bestd = d;\n                    nearest_idx[i] = j;\n                }\n            }\n        }\n\n        start_time = chrono::steady_clock::now();\n\n        vector<Rect> best_rects = initial_rects();\n        long double best_score = total_score(best_rects);\n\n        // Initial constructive runs\n        for (int t = 0; t < 8; ++t) {\n            vector<Rect> cur = initial_rects();\n            Params p = random_constructive_params();\n            long double sc = optimize(cur, p);\n            if (sc > best_score) {\n                best_score = sc;\n                best_rects = move(cur);\n            }\n        }\n\n        int iter = 0;\n        while (elapsed_sec() < 4.75L) {\n            vector<Rect> cur;\n            Params p;\n\n            if (iter < 10 || rng.uniform() < 0.70L) {\n                cur = initial_rects();\n                p = random_constructive_params();\n            } else {\n                cur = perturb_from_best(best_rects);\n                p = random_perturb_params();\n            }\n\n            long double sc = optimize(cur, p);\n            if (sc > best_score) {\n                best_score = sc;\n                best_rects = move(cur);\n            }\n            ++iter;\n        }\n\n        for (int i = 0; i < n; ++i) {\n            cout << best_rects[i].l << ' ' << best_rects[i].b << ' '\n                 << best_rects[i].r << ' ' << best_rects[i].t << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50;\nstatic constexpr int W = 50;\nstatic constexpr int V = H * W;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463325252ull;\n    void seed(uint64_t s) { x = (s ? s : 88172645463325252ull); }\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\nstruct Params {\n    int lookDepth;\n    int tilesMargin;\n    int ubMargin;\n    int lookMargin;\n};\n\nstruct Path {\n    vector<int> pos;\n    vector<int> prefixScore;\n    vector<unsigned char> branchCnt;\n    vector<int> branchPoints;\n    int score = 0;\n};\n\nint si, sj;\nint startIdx;\nint tileId[V];\nint pval[V];\nint M;\n\nint adjList[V][4];\nunsigned char adjCnt[V];\n\nvector<int> tileMaxVal;\nvector<unsigned char> usedTile;\nvector<unsigned char> tmpUsed;\n\nint visSq[V];\nvector<int> visTile;\nint bfsStamp = 1;\nint tileStamp = 1;\nint qbuf[V];\n\nusing Clock = chrono::steady_clock;\n\ninline int id(int i, int j) { return i * W + j; }\n\nstruct CompStat {\n    int tiles;\n    int ub;\n};\n\ninline CompStat component_stat(int s) {\n    const int st = tileId[s];\n    ++bfsStamp;\n    ++tileStamp;\n\n    int head = 0, tail = 0;\n    qbuf[tail++] = s;\n    visSq[s] = bfsStamp;\n    visTile[st] = tileStamp;\n\n    int tiles = 1;\n    int ub = pval[s];\n\n    while (head < tail) {\n        int u = qbuf[head++];\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            int tv = tileId[v];\n            if (tv == st || usedTile[tv]) continue;\n\n            if (visSq[v] != bfsStamp) {\n                visSq[v] = bfsStamp;\n                qbuf[tail++] = v;\n            }\n            if (visTile[tv] != tileStamp) {\n                visTile[tv] = tileStamp;\n                ++tiles;\n                ub += tileMaxVal[tv];\n            }\n        }\n    }\n    return {tiles, ub};\n}\n\nint local_dfs(int u, int depth) {\n    if (depth == 0) return 0;\n\n    int cand[4];\n    int cnt = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) cand[cnt++] = v;\n    }\n    if (cnt == 0) return 0;\n\n    int best = 0;\n    for (int i = 0; i < cnt; ++i) {\n        int v = cand[i];\n        int tv = tileId[v];\n        usedTile[tv] = 1;\n        int sc = pval[v] + local_dfs(v, depth - 1);\n        usedTile[tv] = 0;\n        if (sc > best) best = sc;\n    }\n    return best;\n}\n\ninline int degree_after_move(int u) {\n    int cnt = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) ++cnt;\n    }\n    return cnt;\n}\n\nParams random_params(bool restart) {\n    Params p;\n    if (restart) {\n        p.lookDepth = 6;\n        p.tilesMargin = (rng.next_double() < 0.50 ? 1 : 0);\n        p.ubMargin = 120 + rng.next_int(0, 120);\n        p.lookMargin = 10 + rng.next_int(0, 15);\n    } else {\n        p.lookDepth = 5 + rng.next_int(0, 1);\n        p.tilesMargin = (rng.next_double() < 0.30 ? 1 : 0);\n        p.ubMargin = 80 + rng.next_int(0, 80);\n        p.lookMargin = 5 + rng.next_int(0, 10);\n    }\n    return p;\n}\n\nbool better_path(const Path& a, const Path& b) {\n    if (a.score != b.score) return a.score > b.score;\n    return a.pos.size() > b.pos.size();\n}\n\nvoid prepare_path(Path& path) {\n    int n = (int)path.pos.size();\n    path.prefixScore.assign(n, 0);\n    path.branchCnt.assign(n, 0);\n    path.branchPoints.clear();\n\n    fill(tmpUsed.begin(), tmpUsed.end(), 0);\n    int s = 0;\n    for (int i = 0; i < n; ++i) {\n        int u = path.pos[i];\n        tmpUsed[tileId[u]] = 1;\n        s += pval[u];\n        path.prefixScore[i] = s;\n\n        int cnt = 0;\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            if (!tmpUsed[tileId[v]]) ++cnt;\n        }\n        path.branchCnt[i] = (unsigned char)cnt;\n        if (cnt >= 2) path.branchPoints.push_back(i);\n    }\n    path.score = s;\n}\n\nPath build_path(vector<int> pos, int score, const Params& prm, const Clock::time_point& deadline) {\n    Path res;\n    res.pos = std::move(pos);\n    res.pos.reserve(V);\n    res.score = score;\n\n    int stepCounter = 0;\n\n    while (true) {\n        if ((stepCounter++ & 31) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n\n        int u = res.pos.back();\n        int cand[4];\n        int ccnt = 0;\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            if (!usedTile[tileId[v]]) cand[ccnt++] = v;\n        }\n\n        if (ccnt == 0) break;\n\n        int chosen = cand[0];\n\n        if (ccnt >= 2) {\n            struct Info {\n                int v;\n                int tiles;\n                int ub;\n                int look;\n            };\n            Info info[4];\n\n            int maxTiles = -1;\n            for (int i = 0; i < ccnt; ++i) {\n                auto cs = component_stat(cand[i]);\n                info[i] = {cand[i], cs.tiles, cs.ub, 0};\n                if (cs.tiles > maxTiles) maxTiles = cs.tiles;\n            }\n\n            int idx1[4], n1 = 0;\n            int bestUB = -1;\n            for (int i = 0; i < ccnt; ++i) {\n                if (info[i].tiles >= maxTiles - prm.tilesMargin) {\n                    idx1[n1++] = i;\n                    if (info[i].ub > bestUB) bestUB = info[i].ub;\n                }\n            }\n\n            int idx2[4], n2 = 0;\n            for (int t = 0; t < n1; ++t) {\n                int i = idx1[t];\n                if (info[i].ub >= bestUB - prm.ubMargin) {\n                    idx2[n2++] = i;\n                }\n            }\n\n            if (n2 == 1) {\n                chosen = info[idx2[0]].v;\n            } else {\n                int bestLook = -1;\n                for (int t = 0; t < n2; ++t) {\n                    int i = idx2[t];\n                    int v = info[i].v;\n                    int tv = tileId[v];\n                    usedTile[tv] = 1;\n                    int look = pval[v] + local_dfs(v, prm.lookDepth - 1);\n                    int deg = degree_after_move(v);\n                    usedTile[tv] = 0;\n                    look += 3 * (4 - deg); // constrained hand slightly preferred\n                    info[i].look = look;\n                    if (look > bestLook) bestLook = look;\n                }\n\n                int finalIdx[4], nf = 0;\n                int weights[4];\n                int sumW = 0;\n\n                for (int t = 0; t < n2; ++t) {\n                    int i = idx2[t];\n                    if (info[i].look >= bestLook - prm.lookMargin) {\n                        finalIdx[nf] = i;\n                        int w = info[i].look - (bestLook - prm.lookMargin) + 1;\n                        weights[nf] = w;\n                        sumW += w;\n                        ++nf;\n                    }\n                }\n\n                int r = rng.next_int(1, sumW);\n                chosen = info[finalIdx[0]].v;\n                for (int t = 0; t < nf; ++t) {\n                    r -= weights[t];\n                    if (r <= 0) {\n                        chosen = info[finalIdx[t]].v;\n                        break;\n                    }\n                }\n            }\n        }\n\n        usedTile[tileId[chosen]] = 1;\n        res.pos.push_back(chosen);\n        res.score += pval[chosen];\n    }\n\n    return res;\n}\n\nint choose_cut(const Path& best) {\n    if (best.branchPoints.empty()) return 0;\n    const auto& bp = best.branchPoints;\n    int n = (int)bp.size();\n\n    int l = 0, r = n - 1;\n    if (n >= 3) {\n        int a = n / 3;\n        int b = (2 * n) / 3;\n        double x = rng.next_double();\n        if (x < 0.20) {\n            l = 0;\n            r = max(0, a - 1);\n        } else if (x < 0.60) {\n            l = a;\n            r = max(a, b - 1);\n        } else {\n            l = b;\n            r = n - 1;\n        }\n    }\n    return bp[l + rng.next_int(0, r - l)];\n}\n\nstring to_answer(const vector<int>& pos) {\n    string ans;\n    if (pos.size() <= 1) return ans;\n    ans.reserve(pos.size() - 1);\n    for (size_t i = 1; i < pos.size(); ++i) {\n        int d = pos[i] - pos[i - 1];\n        if (d == -W) ans.push_back('U');\n        else if (d == W) ans.push_back('D');\n        else if (d == -1) ans.push_back('L');\n        else if (d == 1) ans.push_back('R');\n    }\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj;\n    startIdx = id(si, sj);\n\n    int maxTile = -1;\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int t;\n            cin >> t;\n            tileId[id(i, j)] = t;\n            maxTile = max(maxTile, t);\n        }\n    }\n    M = maxTile + 1;\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            cin >> pval[id(i, j)];\n        }\n    }\n\n    tileMaxVal.assign(M, 0);\n    for (int v = 0; v < V; ++v) {\n        tileMaxVal[tileId[v]] = max(tileMaxVal[tileId[v]], pval[v]);\n    }\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int u = id(i, j);\n            int cnt = 0;\n            const int di[4] = {-1, 1, 0, 0};\n            const int dj[4] = {0, 0, -1, 1};\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + di[dir];\n                int nj = j + dj[dir];\n                if (ni < 0 || ni >= H || nj < 0 || nj >= W) continue;\n                int v = id(ni, nj);\n                if (tileId[v] == tileId[u]) continue;\n                adjList[u][cnt++] = v;\n            }\n            adjCnt[u] = (unsigned char)cnt;\n        }\n    }\n\n    usedTile.assign(M, 0);\n    tmpUsed.assign(M, 0);\n    visTile.assign(M, 0);\n    memset(visSq, 0, sizeof(visSq));\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)startIdx + 0x9e3779b97f4a7c15ull;\n    for (int v = 0; v < V; ++v) {\n        seed = seed * 1000003ull ^ (uint64_t)(tileId[v] + 1);\n        seed = seed * 1000003ull ^ (uint64_t)(pval[v] + 7);\n    }\n    rng.seed(seed);\n\n    auto deadline = Clock::now() + chrono::milliseconds(1950);\n\n    Path best;\n    best.score = -1;\n\n    while (Clock::now() < deadline) {\n        bool restart = (best.score < 0) || best.branchPoints.empty() || (rng.next_double() < 0.18);\n\n        fill(usedTile.begin(), usedTile.end(), 0);\n\n        vector<int> prefix;\n        int prefScore = 0;\n\n        if (restart) {\n            prefix.push_back(startIdx);\n            prefScore = pval[startIdx];\n            usedTile[tileId[startIdx]] = 1;\n        } else {\n            int cut = choose_cut(best);\n            prefix.assign(best.pos.begin(), best.pos.begin() + cut + 1);\n            prefScore = best.prefixScore[cut];\n            for (int i = 0; i <= cut; ++i) {\n                usedTile[tileId[best.pos[i]]] = 1;\n            }\n        }\n\n        Params prm = random_params(restart);\n        Path cand = build_path(std::move(prefix), prefScore, prm, deadline);\n\n        if (best.score < 0 || better_path(cand, best)) {\n            best = std::move(cand);\n            prepare_path(best);\n        }\n    }\n\n    if (best.score < 0) {\n        best.pos = {startIdx};\n    }\n\n    cout << to_answer(best.pos) << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int HN = N * (N - 1);     // 30 * 29 = 870\nstatic constexpr int VN = (N - 1) * N;     // 29 * 30 = 870\nstatic constexpr int E = HN + VN;          // 1740\nstatic constexpr double INIT_COST = 5000.0;\nstatic constexpr double MIN_COST = 1000.0;\nstatic constexpr double MAX_COST = 9000.0;\n\ninline int hid(int i, int j) { return i * 29 + j; }          // h[i][j], 0<=i<30, 0<=j<29\ninline int vid(int i, int j) { return HN + i * 30 + j; }     // v[i][j], 0<=i<29, 0<=j<30\ninline int node_id(int i, int j) { return i * N + j; }\n\nstruct Observation {\n    vector<int> edges;\n    double y;\n    double w; // weight = 1 / path_length\n};\n\nstruct Path {\n    string s;\n    vector<int> edges;\n    double raw_cost = 0.0; // sum of current estimated edge costs (without any search penalty)\n};\n\nstruct Solver {\n    vector<double> x;          // current edge estimates\n    vector<int> vis;           // how many times each edge has been used\n    vector<Observation> hist;  // past observations\n\n    mt19937 rng;\n\n    Solver() : x(E, INIT_COST), vis(E, 0) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        hist.reserve(1000);\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    int randint(int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    }\n\n    double exploration_score(const Path& p, double bonus) const {\n        double score = p.raw_cost;\n        for (int e : p.edges) {\n            score -= bonus / sqrt((double)vis[e] + 1.0);\n        }\n        return score;\n    }\n\n    Path random_monotone_path(int si, int sj, int ti, int tj) {\n        Path p;\n        int i = si, j = sj;\n        int rv = abs(ti - si);\n        int rh = abs(tj - sj);\n        char mv_v = (ti > si ? 'D' : 'U');\n        char mv_h = (tj > sj ? 'R' : 'L');\n\n        p.s.reserve(rv + rh);\n        p.edges.reserve(rv + rh);\n\n        while (rv > 0 || rh > 0) {\n            bool take_v;\n            if (rv == 0) take_v = false;\n            else if (rh == 0) take_v = true;\n            else take_v = (randint(1, rv + rh) <= rv);\n\n            if (take_v) {\n                if (mv_v == 'D') {\n                    int e = vid(i, j);\n                    p.s.push_back('D');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    ++i;\n                } else {\n                    int e = vid(i - 1, j);\n                    p.s.push_back('U');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    --i;\n                }\n                --rv;\n            } else {\n                if (mv_h == 'R') {\n                    int e = hid(i, j);\n                    p.s.push_back('R');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    ++j;\n                } else {\n                    int e = hid(i, j - 1);\n                    p.s.push_back('L');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    --j;\n                }\n                --rh;\n            }\n        }\n        return p;\n    }\n\n    Path dijkstra_path(int si, int sj, int ti, int tj, double step_penalty) const {\n        const int V = N * N;\n        const double INF = 1e100;\n\n        vector<double> dist(V, INF);\n        vector<int> parent(V, -1), parent_edge(V, -1);\n        vector<char> parent_char(V, '?');\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        int s = node_id(si, sj);\n        int t = node_id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        auto relax = [&](int v, int ni, int nj, int e, char c, double w) {\n            int nv = node_id(ni, nj);\n            double nd = dist[v] + w;\n            if (nd + 1e-12 < dist[nv]) {\n                dist[nv] = nd;\n                parent[nv] = v;\n                parent_edge[nv] = e;\n                parent_char[nv] = c;\n                pq.push({nd, nv});\n            }\n        };\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d > dist[v] + 1e-12) continue;\n            if (v == t) break;\n\n            int i = v / N;\n            int j = v % N;\n\n            if (i > 0) {\n                int e = vid(i - 1, j);\n                relax(v, i - 1, j, e, 'U', x[e] + step_penalty);\n            }\n            if (i + 1 < N) {\n                int e = vid(i, j);\n                relax(v, i + 1, j, e, 'D', x[e] + step_penalty);\n            }\n            if (j > 0) {\n                int e = hid(i, j - 1);\n                relax(v, i, j - 1, e, 'L', x[e] + step_penalty);\n            }\n            if (j + 1 < N) {\n                int e = hid(i, j);\n                relax(v, i, j + 1, e, 'R', x[e] + step_penalty);\n            }\n        }\n\n        Path res;\n        vector<char> rs;\n        vector<int> re;\n\n        for (int cur = t; cur != s; cur = parent[cur]) {\n            rs.push_back(parent_char[cur]);\n            re.push_back(parent_edge[cur]);\n        }\n        reverse(rs.begin(), rs.end());\n        reverse(re.begin(), re.end());\n\n        res.s.assign(rs.begin(), rs.end());\n        res.edges = move(re);\n        res.raw_cost = 0.0;\n        for (int e : res.edges) res.raw_cost += x[e];\n        return res;\n    }\n\n    static double dot_vec(const vector<double>& a, const vector<double>& b) {\n        double s = 0.0;\n        for (int i = 0; i < (int)a.size(); ++i) s += a[i] * b[i];\n        return s;\n    }\n\n    void fit_piecewise_29(const array<double, 29>& val,\n                          const array<double, 29>& wt,\n                          array<double, 29>& out) {\n        array<double, 30> W{}, S{}, Q{};\n        for (int i = 0; i < 29; ++i) {\n            W[i + 1] = W[i] + wt[i];\n            S[i + 1] = S[i] + wt[i] * val[i];\n            Q[i + 1] = Q[i] + wt[i] * val[i] * val[i];\n        }\n\n        auto seg = [&](int l, int r) -> pair<double, double> {\n            double w = W[r + 1] - W[l];\n            double s = S[r + 1] - S[l];\n            double q = Q[r + 1] - Q[l];\n            double mean = s / max(w, 1e-9);\n            double err = q - s * s / max(w, 1e-9);\n            return {mean, err};\n        };\n\n        auto [m1, e1] = seg(0, 28);\n\n        double best2 = 1e100;\n        int bestk = -1;\n        double ml = m1, mr = m1;\n        for (int k = 1; k <= 28; ++k) {\n            auto [a, ea] = seg(0, k - 1);\n            auto [b, eb] = seg(k, 28);\n            double tot = ea + eb;\n            if (tot < best2) {\n                best2 = tot;\n                bestk = k;\n                ml = a;\n                mr = b;\n            }\n        }\n\n        bool use_one = false;\n        if (bestk == -1) use_one = true;\n        if (best2 > e1 * 0.94) use_one = true;\n        if (fabs(ml - mr) < 150.0) use_one = true;\n\n        if (use_one) {\n            for (int i = 0; i < 29; ++i) out[i] = m1;\n        } else {\n            for (int i = 0; i < bestk; ++i) out[i] = ml;\n            for (int i = bestk; i < 29; ++i) out[i] = mr;\n        }\n    }\n\n    void piecewise_project() {\n        // Horizontal rows\n        for (int i = 0; i < 30; ++i) {\n            array<double, 29> val{}, wt{}, tgt{};\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                val[j] = x[e];\n                wt[j] = vis[e] + 3.0;\n            }\n            fit_piecewise_29(val, wt, tgt);\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                double beta = min(0.30, 0.45 / sqrt((double)vis[e] + 2.0));\n                x[e] = clamp((1.0 - beta) * x[e] + beta * tgt[j], MIN_COST, MAX_COST);\n            }\n        }\n\n        // Vertical columns\n        for (int j = 0; j < 30; ++j) {\n            array<double, 29> val{}, wt{}, tgt{};\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                val[i] = x[e];\n                wt[i] = vis[e] + 3.0;\n            }\n            fit_piecewise_29(val, wt, tgt);\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                double beta = min(0.30, 0.45 / sqrt((double)vis[e] + 2.0));\n                x[e] = clamp((1.0 - beta) * x[e] + beta * tgt[i], MIN_COST, MAX_COST);\n            }\n        }\n    }\n\n    void global_refine() {\n        int nobs = (int)hist.size();\n        if (nobs == 0) return;\n\n        // Regularization decays slightly as more observations accumulate.\n        double lambda0 = 0.10 / sqrt(nobs + 1.0) + 0.015; // weak prior to 5000\n        double lambda1 = 0.35 / sqrt(nobs + 1.0) + 0.035; // smoothness along rows/columns\n\n        vector<double> rhs(E, lambda0 * INIT_COST);\n        for (const auto& ob : hist) {\n            double c = ob.w * ob.y;\n            for (int e : ob.edges) rhs[e] += c;\n        }\n\n        auto apply = [&](const vector<double>& p, vector<double>& out) {\n            out.assign(E, 0.0);\n\n            // prior\n            for (int e = 0; e < E; ++e) out[e] = lambda0 * p[e];\n\n            // data term: sum w * a a^T p\n            for (const auto& ob : hist) {\n                double s = 0.0;\n                for (int e : ob.edges) s += p[e];\n                s *= ob.w;\n                for (int e : ob.edges) out[e] += s;\n            }\n\n            // smoothness along horizontal rows\n            for (int i = 0; i < 30; ++i) {\n                for (int j = 0; j < 28; ++j) {\n                    int e1 = hid(i, j);\n                    int e2 = hid(i, j + 1);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n\n            // smoothness along vertical columns\n            for (int j = 0; j < 30; ++j) {\n                for (int i = 0; i < 28; ++i) {\n                    int e1 = vid(i, j);\n                    int e2 = vid(i + 1, j);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n        };\n\n        vector<double> sol = x, r(E), p(E), Ap(E);\n        apply(sol, Ap);\n        for (int e = 0; e < E; ++e) r[e] = rhs[e] - Ap[e];\n        p = r;\n\n        double rs0 = dot_vec(r, r);\n        double rs = rs0;\n        if (rs < 1e-12) return;\n\n        const int ITERS = 25;\n        for (int it = 0; it < ITERS; ++it) {\n            apply(p, Ap);\n            double pAp = dot_vec(p, Ap);\n            if (pAp <= 1e-18) break;\n            double alpha = rs / pAp;\n\n            for (int e = 0; e < E; ++e) sol[e] += alpha * p[e];\n            for (int e = 0; e < E; ++e) r[e] -= alpha * Ap[e];\n\n            double rs_new = dot_vec(r, r);\n            if (rs_new < rs0 * 1e-10) break;\n\n            double beta = rs_new / rs;\n            for (int e = 0; e < E; ++e) p[e] = r[e] + beta * p[e];\n            rs = rs_new;\n        }\n\n        for (int e = 0; e < E; ++e) x[e] = clamp(sol[e], MIN_COST, MAX_COST);\n\n        // Extra projection exploiting M in {1,2}\n        piecewise_project();\n    }\n\n    void online_update(const Path& path, double y, int qidx) {\n        const int m = (int)path.edges.size();\n        if (m == 0) return;\n\n        double pred = path.raw_cost;\n        double residual = y - pred;\n\n        double eta;\n        if (qidx < 120) eta = 0.35;\n        else if (qidx < 350) eta = 0.24;\n        else eta = 0.18;\n\n        vector<double> u(m);\n        double su = 0.0;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            u[k] = 1.0 / sqrt((double)vis[e] + 1.0);\n            su += u[k];\n        }\n        if (su < 1e-12) su = 1.0;\n\n        double scale = eta * residual / su;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            double delta = scale * u[k];\n            delta = clamp(delta, -1000.0, 1000.0);\n            x[e] = clamp(x[e] + delta, MIN_COST, MAX_COST);\n        }\n        for (int e : path.edges) vis[e]++;\n\n        hist.push_back({path.edges, y, 1.0 / m});\n    }\n\n    Path choose_path(int si, int sj, int ti, int tj, int qidx) {\n        bool explore = false;\n        double bonus = 0.0;\n        int samples = 0;\n\n        if (qidx < 150) {\n            explore = true;\n            bonus = 260.0;\n            samples = 24;\n        } else if (qidx < 400 && rand01() < 0.06) {\n            explore = true;\n            bonus = 120.0;\n            samples = 10;\n        }\n\n        double step_penalty = 300.0 * max(0.0, 1.0 - qidx / 500.0);\n\n        if (!explore) {\n            return dijkstra_path(si, sj, ti, tj, step_penalty);\n        }\n\n        Path best = random_monotone_path(si, sj, ti, tj);\n        double best_score = exploration_score(best, bonus);\n\n        for (int t = 1; t < samples; ++t) {\n            Path cand = random_monotone_path(si, sj, ti, tj);\n            double sc = exploration_score(cand, bonus);\n            if (sc < best_score || (fabs(sc - best_score) < 1e-9 && randint(0, 1))) {\n                best = move(cand);\n                best_score = sc;\n            }\n        }\n\n        Path dijk = dijkstra_path(si, sj, ti, tj, step_penalty);\n        double dsc = exploration_score(dijk, bonus);\n        if (dsc < best_score) best = move(dijk);\n\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        Path path = solver.choose_path(si, sj, ti, tj, q);\n\n        cout << path.s << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.online_update(path, (double)result, q);\n\n        bool do_refine = false;\n        int qq = q + 1;\n        if (qq <= 200) {\n            if (qq % 20 == 0) do_refine = true;\n        } else {\n            if (qq % 40 == 0) do_refine = true;\n        }\n\n        if (do_refine) {\n            solver.global_refine();\n        }\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\n\nstruct Candidate {\n    string row;          // length 20\n    vector<int> cover;   // ids of unique strings covered\n    int totalWeight = 0;\n};\n\nstruct Move {\n    long long val;\n    string s;\n};\n\nmt19937 rng((unsigned)chrono::steady_clock::now().time_since_epoch().count());\n\nvector<string> pats;   // unique strings\nvector<int> wt;        // multiplicity\nvector<int> impOrder;  // importance order\n\ninline bool contains_in_doubled(const char* dd, const string& p) {\n    const int k = (int)p.size();\n    const char* ps = p.data();\n    for (int st = 0; st < N; ++st) {\n        int j = 0;\n        while (j < k && dd[st + j] == ps[j]) ++j;\n        if (j == k) return true;\n    }\n    return false;\n}\n\nint overlap_suffix_prefix(const string& a, const string& b) {\n    int lim = min((int)a.size(), (int)b.size());\n    for (int o = lim; o >= 1; --o) {\n        bool ok = true;\n        int sa = (int)a.size() - o;\n        for (int i = 0; i < o; ++i) {\n            if (a[sa + i] != b[i]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) return o;\n    }\n    return 0;\n}\n\nstring repeat_to_20(const string& s) {\n    if ((int)s.size() == N) return s;\n    string r(N, 'A');\n    for (int i = 0; i < N; ++i) r[i] = s[i % (int)s.size()];\n    return r;\n}\n\nstring min_rotation(const string& s) {\n    string best = s;\n    for (int sh = 1; sh < N; ++sh) {\n        string t = s.substr(sh) + s.substr(0, sh);\n        if (t < best) best = t;\n    }\n    return best;\n}\n\nvoid push_top(vector<Move>& top, long long val, const string& s, int cap = 4) {\n    if (val <= 0) return;\n    Move mv{val, s};\n    int pos = (int)top.size();\n    top.push_back(mv);\n    while (pos > 0 && top[pos].val > top[pos - 1].val) {\n        swap(top[pos], top[pos - 1]);\n        --pos;\n    }\n    if ((int)top.size() > cap) top.pop_back();\n}\n\nstring choose_move(const vector<Move>& top, bool randomized) {\n    if (top.empty()) return \"\";\n    if (!randomized || (int)top.size() == 1) return top[0].s;\n    int k = min<int>(3, top.size());\n    int r = (int)(rng() % 10);\n    int idx = 0;\n    if (k >= 3) {\n        if (r < 6) idx = 0;\n        else if (r < 9) idx = 1;\n        else idx = 2;\n    } else if (k == 2) {\n        idx = (r < 7 ? 0 : 1);\n    } else {\n        idx = 0;\n    }\n    return top[idx].s;\n}\n\nstring build_candidate_row(int seedId, bool randomized) {\n    string cur = pats[seedId];\n\n    // phase 0: prioritize strong overlap / containment\n    for (int iter = 0; iter < 25 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int id : impOrder) {\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            // If x contains cur, jump to x.\n            if ((int)x.size() > (int)cur.size()) {\n                if (x.find(cur) != string::npos && (int)x.size() <= N) {\n                    long long val = 1LL * wt[id] * 3000 + 1LL * ((int)x.size() - (int)cur.size()) * 200;\n                    push_top(top, val, x);\n                }\n            }\n\n            // append right with overlap\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n\n            // prepend left with overlap\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty()) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    // phase 1: pack additional useful strings while length <= 20\n    for (int iter = 0; iter < 25 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int id : impOrder) {\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            // append right\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n\n            // prepend left\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty()) break;\n        if (top[0].val <= 0) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    return repeat_to_20(cur);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startClock = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - startClock\n        ).count();\n    };\n\n    int N_in, M;\n    cin >> N_in >> M;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M * 2);\n\n    vector<int> charFreq(8, 0);\n    for (int i = 0; i < M; ++i) {\n        string s;\n        cin >> s;\n        if (!mp.count(s)) {\n            int id = (int)pats.size();\n            mp[s] = id;\n            pats.push_back(s);\n            wt.push_back(1);\n        } else {\n            wt[mp[s]]++;\n        }\n        for (char c : s) charFreq[c - 'A']++;\n    }\n\n    int U = (int)pats.size();\n\n    // Importance: frequent and long strings are good seeds\n    vector<long long> imp(U);\n    for (int i = 0; i < U; ++i) {\n        int L = (int)pats[i].size();\n        imp[i] = 1LL * wt[i] * L * L;\n    }\n    impOrder.resize(U);\n    iota(impOrder.begin(), impOrder.end(), 0);\n    sort(impOrder.begin(), impOrder.end(), [&](int a, int b) {\n        if (imp[a] != imp[b]) return imp[a] > imp[b];\n        return pats[a].size() > pats[b].size();\n    });\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) {\n        if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n    }\n\n    vector<Candidate> cands;\n    cands.reserve(512);\n    unordered_set<string> seen;\n    seen.reserve(2048);\n\n    auto add_candidate = [&](string row) {\n        if ((int)row.size() != N) row = repeat_to_20(row);\n        row = min_rotation(row);\n        if (!seen.insert(row).second) return;\n\n        char dd[40];\n        for (int i = 0; i < N; ++i) dd[i] = dd[i + N] = row[i];\n\n        Candidate cand;\n        cand.row = row;\n        cand.totalWeight = 0;\n        for (int id = 0; id < U; ++id) {\n            if (contains_in_doubled(dd, pats[id])) {\n                cand.cover.push_back(id);\n                cand.totalWeight += wt[id];\n            }\n        }\n        if (!cand.cover.empty()) cands.push_back(std::move(cand));\n    };\n\n    // Basic fallback rows\n    for (int c = 0; c < 8; ++c) {\n        add_candidate(string(N, char('A' + c)));\n    }\n\n    // Pure repeated seed strings\n    {\n        int lim = min(U, 60);\n        for (int t = 0; t < lim; ++t) {\n            add_candidate(repeat_to_20(pats[impOrder[t]]));\n        }\n    }\n\n    // Deterministic builds from strong seeds\n    {\n        int lim = min(U, 100);\n        for (int t = 0; t < lim; ++t) {\n            add_candidate(build_candidate_row(impOrder[t], false));\n            if (elapsed_ms() > 1200) break;\n        }\n    }\n\n    // Randomized builds\n    {\n        int trials = 70;\n        for (int t = 0; t < trials; ++t) {\n            int lim = min(U, max(1, 40 + t));\n            int seedId = impOrder[(int)(rng() % lim)];\n            add_candidate(build_candidate_row(seedId, true));\n            if (elapsed_ms() > 1500) break;\n        }\n    }\n\n    // More fallback if somehow too few\n    if ((int)cands.size() < 20) {\n        for (int a = 0; a < 8; ++a) {\n            for (int b = 0; b < 8; ++b) {\n                string s(N, 'A');\n                for (int i = 0; i < N; ++i) s[i] = char('A' + ((i & 1) ? b : a));\n                add_candidate(s);\n                if ((int)cands.size() >= 20) break;\n            }\n            if ((int)cands.size() >= 20) break;\n        }\n    }\n\n    if (cands.empty()) {\n        string row(N, char('A' + bestChar));\n        for (int i = 0; i < N; ++i) cout << row << '\\n';\n        return 0;\n    }\n\n    int C = (int)cands.size();\n\n    // Greedy weighted set cover for 20 rows\n    vector<int> selected;\n    selected.reserve(20);\n    vector<char> usedCand(C, 0);\n    vector<char> covered(U, 0);\n\n    for (int step = 0; step < 20 && step < C; ++step) {\n        int best = -1;\n        long long bestGain = -1;\n        int bestTotal = -1;\n\n        for (int ci = 0; ci < C; ++ci) if (!usedCand[ci]) {\n            long long gain = 0;\n            for (int id : cands[ci].cover) {\n                if (!covered[id]) gain += wt[id];\n            }\n            if (gain > bestGain || (gain == bestGain && cands[ci].totalWeight > bestTotal)) {\n                bestGain = gain;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n\n        if (best == -1) break;\n        usedCand[best] = 1;\n        selected.push_back(best);\n        for (int id : cands[best].cover) covered[id] = 1;\n    }\n\n    // Fill up to 20 rows if needed\n    if ((int)selected.size() < 20) {\n        vector<int> ord(C);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return cands[a].totalWeight > cands[b].totalWeight;\n        });\n        for (int ci : ord) {\n            if ((int)selected.size() >= 20) break;\n            if (!usedCand[ci]) {\n                usedCand[ci] = 1;\n                selected.push_back(ci);\n            }\n        }\n    }\n    while ((int)selected.size() < 20) selected.push_back(selected[0]);\n\n    // Local replacement improvement on row-only coverage\n    vector<int> coverCnt(U, 0);\n    long long rowWeight = 0;\n    fill(usedCand.begin(), usedCand.end(), 0);\n    for (int ci : selected) usedCand[ci] = 1;\n    for (int ci : selected) {\n        for (int id : cands[ci].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    for (int pass = 0; pass < 2; ++pass) {\n        bool improved = false;\n        for (int pos = 0; pos < 20; ++pos) {\n            int old = selected[pos];\n            usedCand[old] = 0;\n            for (int id : cands[old].cover) {\n                if (--coverCnt[id] == 0) rowWeight -= wt[id];\n            }\n\n            int best = old;\n            long long bestScore = rowWeight;\n            int bestTotal = cands[old].totalWeight;\n\n            for (int ci = 0; ci < C; ++ci) {\n                if (usedCand[ci]) continue;\n                long long sc = rowWeight;\n                for (int id : cands[ci].cover) {\n                    if (coverCnt[id] == 0) sc += wt[id];\n                }\n                if (sc > bestScore || (sc == bestScore && cands[ci].totalWeight > bestTotal)) {\n                    bestScore = sc;\n                    bestTotal = cands[ci].totalWeight;\n                    best = ci;\n                }\n            }\n\n            selected[pos] = best;\n            usedCand[best] = 1;\n            for (int id : cands[best].cover) {\n                if (coverCnt[id]++ == 0) rowWeight += wt[id];\n            }\n            if (best != old) improved = true;\n        }\n        if (!improved) break;\n    }\n\n    // Build selected row list\n    vector<string> rows(20);\n    for (int i = 0; i < 20; ++i) rows[i] = cands[selected[i]].row;\n\n    vector<int> notRowIds;\n    notRowIds.reserve(U);\n    for (int id = 0; id < U; ++id) {\n        if (coverCnt[id] == 0) notRowIds.push_back(id);\n    }\n\n    // Precompute shifted rows: shifted[r][sh][c]\n    vector<array<array<char, N>, N>> shifted(20);\n    for (int r = 0; r < 20; ++r) {\n        for (int sh = 0; sh < N; ++sh) {\n            for (int c = 0; c < N; ++c) {\n                shifted[r][sh][c] = rows[r][(c + sh) % N];\n            }\n        }\n    }\n\n    auto eval_exact = [&](const vector<int>& order, const vector<int>& shifts) -> long long {\n        array<array<char, 40>, 20> cold{};\n        for (int rr = 0; rr < 20; ++rr) {\n            const auto& sr = shifted[order[rr]][shifts[rr]];\n            for (int c = 0; c < 20; ++c) {\n                cold[c][rr] = sr[c];\n                cold[c][rr + 20] = sr[c];\n            }\n        }\n\n        long long total = rowWeight;\n        for (int id : notRowIds) {\n            bool ok = false;\n            for (int c = 0; c < 20 && !ok; ++c) {\n                if (contains_in_doubled(cold[c].data(), pats[id])) ok = true;\n            }\n            if (ok) total += wt[id];\n        }\n        return total;\n    };\n\n    auto optimize_shifts = [&](vector<int>& order, vector<int>& shifts, long long& curScore, int maxPass) {\n        for (int pass = 0; pass < maxPass; ++pass) {\n            if (elapsed_ms() > 2800) break;\n            bool improved = false;\n            for (int pos = 0; pos < 20; ++pos) {\n                if (elapsed_ms() > 2800) break;\n                int old = shifts[pos];\n                int bestSh = old;\n                long long bestScore = curScore;\n                for (int sh = 0; sh < 20; ++sh) {\n                    if (sh == old) continue;\n                    shifts[pos] = sh;\n                    long long sc = eval_exact(order, shifts);\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestSh = sh;\n                    }\n                }\n                shifts[pos] = bestSh;\n                if (bestScore > curScore) {\n                    curScore = bestScore;\n                    improved = true;\n                }\n            }\n            if (!improved) break;\n        }\n    };\n\n    // Choose a start order among a few random shuffles\n    vector<int> bestOrder(20), bestShifts(20, 0);\n    iota(bestOrder.begin(), bestOrder.end(), 0);\n    long long bestScore = eval_exact(bestOrder, bestShifts);\n\n    for (int t = 0; t < 6; ++t) {\n        if (elapsed_ms() > 2300) break;\n        vector<int> ord(20), sh(20, 0);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n        long long sc = eval_exact(ord, sh);\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestOrder = ord;\n            bestShifts = sh;\n        }\n    }\n\n    // Coordinate descent on shifts\n    optimize_shifts(bestOrder, bestShifts, bestScore, 2);\n\n    // Random swap hill-climb on row order\n    for (int it = 0; it < 30; ++it) {\n        if (elapsed_ms() > 2850) break;\n        int i = (int)(rng() % 20);\n        int j = (int)(rng() % 20);\n        if (i == j) continue;\n        if (i > j) swap(i, j);\n\n        swap(bestOrder[i], bestOrder[j]);\n        swap(bestShifts[i], bestShifts[j]);\n\n        long long sc = eval_exact(bestOrder, bestShifts);\n        if (sc >= bestScore) {\n            bestScore = sc;\n\n            // optimize the two swapped rows' shifts\n            for (int pos : {i, j}) {\n                int old = bestShifts[pos];\n                int bestSh = old;\n                long long localBest = bestScore;\n                for (int sh = 0; sh < 20; ++sh) {\n                    if (sh == old) continue;\n                    bestShifts[pos] = sh;\n                    long long tsc = eval_exact(bestOrder, bestShifts);\n                    if (tsc > localBest) {\n                        localBest = tsc;\n                        bestSh = sh;\n                    }\n                }\n                bestShifts[pos] = bestSh;\n                bestScore = localBest;\n            }\n        } else {\n            swap(bestOrder[i], bestOrder[j]);\n            swap(bestShifts[i], bestShifts[j]);\n        }\n    }\n\n    // Final light shift refinement if time remains\n    if (elapsed_ms() < 2850) {\n        optimize_shifts(bestOrder, bestShifts, bestScore, 1);\n    }\n\n    // Output\n    for (int r = 0; r < 20; ++r) {\n        string out(N, 'A');\n        const auto& sr = shifted[bestOrder[r]][bestShifts[r]];\n        for (int c = 0; c < 20; ++c) out[c] = sr[c];\n        cout << out << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\n\nstatic constexpr int INF_INT = 1e9;\nstatic constexpr ll INF_LL = (ll)4e15;\n\nstruct Task {\n    // type: 0=fixed cell, 1=horizontal segment, 2=vertical segment\n    int type;\n    int seg;\n    int cell;\n};\n\nstruct CandidateResult {\n    bool valid = false;\n    ll cost = (1LL << 60);\n    string path;\n};\n\nint N, si, sj;\nvector<string> gridc;\nvector<vector<int>> idg;\n\nint Rcnt;\nint sId;\nvector<int> rr, cc, cellW;\nvector<vector<int>> nbrs;\n\nint Hcnt, Vcnt;\nvector<int> hid, vid;\nvector<vector<int>> cellsH, cellsV;\nvector<vector<pair<int,int>>> adjHFull, adjHRes; // (v, cell)\n\nint sH, sV;\nvector<char> activeH, activeV;\nvector<int> bestCellH, bestCellV;\nvector<int> distStart;\n\nchrono::steady_clock::time_point globalStart;\n\nll elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - globalStart\n    ).count();\n}\n\nchar dirChar(int a, int b) {\n    if (rr[b] == rr[a] - 1 && cc[b] == cc[a]) return 'U';\n    if (rr[b] == rr[a] + 1 && cc[b] == cc[a]) return 'D';\n    if (rr[b] == rr[a] && cc[b] == cc[a] - 1) return 'L';\n    if (rr[b] == rr[a] && cc[b] == cc[a] + 1) return 'R';\n    return '?';\n}\n\nvoid runDijkstra(int src, vector<int>& dist, vector<int>& parent) {\n    dist.assign(Rcnt, INF_INT);\n    parent.assign(Rcnt, -1);\n    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [d, u] = pq.top();\n        pq.pop();\n        if (d != dist[u]) continue;\n        for (int v : nbrs[u]) {\n            int nd = d + cellW[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                parent[v] = u;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\nvoid hopcroftKarp(\n    const vector<char>& selH,\n    const vector<char>& selV,\n    const vector<vector<pair<int,int>>>& adj,\n    vector<int>& matchH,\n    vector<int>& matchV\n) {\n    matchH.assign(Hcnt, -1);\n    matchV.assign(Vcnt, -1);\n    vector<int> level(Hcnt, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(level.begin(), level.end(), -1);\n        bool found = false;\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) {\n                level[h] = 0;\n                q.push(h);\n            }\n        }\n        while (!q.empty()) {\n            int h = q.front(); q.pop();\n            for (auto [v, cid] : adj[h]) {\n                (void)cid;\n                if (!selV[v]) continue;\n                int h2 = matchV[v];\n                if (h2 == -1) {\n                    found = true;\n                } else if (level[h2] == -1) {\n                    level[h2] = level[h] + 1;\n                    q.push(h2);\n                }\n            }\n        }\n        return found;\n    };\n\n    function<bool(int)> dfs = [&](int h) -> bool {\n        for (auto [v, cid] : adj[h]) {\n            (void)cid;\n            if (!selV[v]) continue;\n            int h2 = matchV[v];\n            if (h2 == -1 || (level[h2] == level[h] + 1 && dfs(h2))) {\n                matchH[h] = v;\n                matchV[v] = h;\n                return true;\n            }\n        }\n        level[h] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) dfs(h);\n        }\n    }\n}\n\npair<vector<char>, vector<char>> buildCanonicalMVC() {\n    vector<char> selH = activeH, selV = activeV;\n    vector<int> matchH, matchV;\n    hopcroftKarp(selH, selV, adjHRes, matchH, matchV);\n\n    vector<char> visH(Hcnt, false), visV(Vcnt, false);\n    queue<int> q;\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h] && matchH[h] == -1) {\n            visH[h] = true;\n            q.push(h);\n        }\n    }\n\n    while (!q.empty()) {\n        int h = q.front(); q.pop();\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (matchH[h] == v) continue; // use only non-matching edges H->V\n            if (!visV[v]) {\n                visV[v] = true;\n                int h2 = matchV[v];\n                if (h2 != -1 && !visH[h2]) {\n                    visH[h2] = true;\n                    q.push(h2);\n                }\n            }\n        }\n    }\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !visH[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && visV[v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\npair<vector<char>, vector<char>> buildWeightedVC(\n    const vector<ll>& wH,\n    const vector<ll>& wV\n) {\n    int S = Hcnt + Vcnt;\n    int T = S + 1;\n    mf_graph<ll> mf(T + 1);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) mf.add_edge(S, h, wH[h]);\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) mf.add_edge(Hcnt + v, T, wV[v]);\n    }\n    for (int h = 0; h < Hcnt; h++) {\n        if (!activeH[h]) continue;\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (!activeV[v]) continue;\n            mf.add_edge(h, Hcnt + v, INF_LL);\n        }\n    }\n\n    mf.flow(S, T);\n    auto reach = mf.min_cut(S);\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h] && !reach[h]) ansH[h] = true;\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v] && reach[Hcnt + v]) ansV[v] = true;\n    }\n    return {ansH, ansV};\n}\n\nvector<Task> buildTasksFromSelected(const vector<char>& selH, const vector<char>& selV) {\n    vector<int> matchH, matchV;\n    hopcroftKarp(selH, selV, adjHFull, matchH, matchV);\n\n    vector<Task> tasks;\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (!selH[h]) continue;\n        if (matchH[h] != -1) {\n            int v = matchH[h];\n            int cid = -1;\n            for (auto [vv, ccid] : adjHFull[h]) {\n                if (vv == v) {\n                    cid = ccid;\n                    break;\n                }\n            }\n            if (cid != -1) tasks.push_back({0, -1, cid});\n        }\n    }\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (selH[h] && matchH[h] == -1) {\n            tasks.push_back({1, h, bestCellH[h]});\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (selV[v] && matchV[v] == -1) {\n            tasks.push_back({2, v, bestCellV[v]});\n        }\n    }\n    return tasks;\n}\n\nvector<int> routeNearestNeighbor(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    vector<int> route;\n    route.reserve(M + 2);\n    route.push_back(0);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    int cur = 0;\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        ll bestD = (1LL << 60);\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeCheapestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    used[0] = true;\n\n    int first = 1;\n    ll bestFirst = (1LL << 60);\n    for (int p = 1; p <= M; p++) {\n        ll val = d0[0][p] + d0[p][0];\n        if (val < bestFirst) {\n            bestFirst = val;\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        ll bestInc = (1LL << 60);\n        int bestP = -1, bestPos = -1;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n                int a = route[pos], b = route[pos + 1];\n                ll inc = d0[a][p] + d0[p][b] - d0[a][b];\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestP = p;\n                    bestPos = pos;\n                }\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, bestP);\n        used[bestP] = true;\n    }\n    return route;\n}\n\nll routeCostMat(const vector<int>& route, const vector<vector<ll>>& mat) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) s += mat[route[i]][route[i + 1]];\n    return s;\n}\n\nvoid improve2opt(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    if (L <= 4) return;\n\n    for (int pass = 0; pass < 4; pass++) {\n        bool improved = false;\n        for (int i = 1; i + 1 < L; i++) {\n            for (int j = i + 1; j + 1 < L; j++) {\n                ll oldv = d0[route[i - 1]][route[i]] + d0[route[j]][route[j + 1]];\n                ll newv = d0[route[i - 1]][route[j]] + d0[route[i]][route[j + 1]];\n                if (newv < oldv) {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nstring reconstructPath(\n    const vector<int>& route,\n    const vector<int>& sourceCells,\n    const vector<vector<int>>& parentAll\n) {\n    string out;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        int aidx = route[i];\n        int bidx = route[i + 1];\n        if (aidx == bidx) continue;\n        int src = sourceCells[aidx];\n        int dst = sourceCells[bidx];\n        vector<int> rev;\n        int cur = dst;\n        while (cur != src) {\n            rev.push_back(cur);\n            cur = parentAll[aidx][cur];\n            if (cur == -1) return \"\";\n        }\n        reverse(rev.begin(), rev.end());\n        int prev = src;\n        for (int x : rev) {\n            char c = dirChar(prev, x);\n            if (c == '?') return \"\";\n            out.push_back(c);\n            prev = x;\n        }\n    }\n    return out;\n}\n\npair<bool,ll> validateAndCost(const string& path) {\n    vector<char> covH(Hcnt, false), covV(Vcnt, false);\n    int cur = sId;\n    covH[hid[cur]] = true;\n    covV[vid[cur]] = true;\n    ll cost = 0;\n\n    for (char ch : path) {\n        int ni = rr[cur], nj = cc[cur];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return {false, 0};\n\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return {false, 0};\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return {false, 0};\n\n        cost += cellW[nxt];\n        cur = nxt;\n        covH[hid[cur]] = true;\n        covV[vid[cur]] = true;\n    }\n\n    if (cur != sId) return {false, 0};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        if (!covH[hid[cid]] && !covV[vid[cid]]) return {false, 0};\n    }\n    return {true, cost};\n}\n\nCandidateResult solveCandidate(vector<Task> tasks) {\n    CandidateResult res;\n    if (tasks.size() > 800) return res;\n    if (elapsed_ms() > 2700) return res;\n\n    if (tasks.empty()) {\n        auto [ok, c] = validateAndCost(\"\");\n        if (ok) {\n            res.valid = true;\n            res.cost = c;\n            res.path = \"\";\n        }\n        return res;\n    }\n\n    vector<int> sourceCells;\n    vector<int> sourceW;\n    vector<vector<int>> distAll, parentAll;\n    vector<vector<ll>> d0, dir0;\n    vector<int> bestRoute;\n\n    auto buildData = [&](const vector<Task>& curTasks) -> bool {\n        int M = (int)curTasks.size() + 1;\n        sourceCells.assign(M, -1);\n        sourceW.assign(M, 0);\n        sourceCells[0] = sId;\n        for (int i = 0; i < (int)curTasks.size(); i++) sourceCells[i + 1] = curTasks[i].cell;\n        for (int i = 0; i < M; i++) sourceW[i] = cellW[sourceCells[i]];\n\n        distAll.assign(M, vector<int>());\n        parentAll.assign(M, vector<int>());\n        for (int i = 0; i < M; i++) {\n            if ((i & 15) == 0 && elapsed_ms() > 2850) return false;\n            runDijkstra(sourceCells[i], distAll[i], parentAll[i]);\n        }\n\n        d0.assign(M, vector<ll>(M, 0));\n        dir0.assign(M, vector<ll>(M, 0));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) {\n                    d0[i][j] = 0;\n                    dir0[i][j] = 0;\n                } else {\n                    dir0[i][j] = distAll[i][sourceCells[j]];\n                    d0[i][j] = dir0[i][j] + sourceW[i];\n                }\n            }\n        }\n        return true;\n    };\n\n    for (int iter = 0; iter < 2; iter++) {\n        if (!buildData(tasks)) return res;\n\n        auto r1 = routeCheapestInsertion(d0);\n        auto r2 = routeNearestNeighbor(d0);\n        improve2opt(r1, d0);\n        improve2opt(r2, d0);\n\n        bestRoute = (routeCostMat(r1, d0) <= routeCostMat(r2, d0) ? r1 : r2);\n\n        if (iter == 0) {\n            int M = (int)tasks.size();\n            vector<int> pos(M + 1, -1);\n            for (int i = 0; i < (int)bestRoute.size(); i++) pos[bestRoute[i]] = i;\n\n            bool changed = false;\n            vector<int> newCells(M);\n            for (int i = 0; i < M; i++) newCells[i] = tasks[i].cell;\n\n            for (int ti = 0; ti < M; ti++) {\n                if (tasks[ti].type == 0) continue;\n\n                int idx = ti + 1;\n                int p = pos[idx];\n                if (p <= 0 || p + 1 >= (int)bestRoute.size()) continue;\n                int prevIdx = bestRoute[p - 1];\n                int nextIdx = bestRoute[p + 1];\n\n                const vector<int>& candCells =\n                    (tasks[ti].type == 1 ? cellsH[tasks[ti].seg] : cellsV[tasks[ti].seg]);\n\n                ll bestVal = (1LL << 60);\n                int bestCid = tasks[ti].cell;\n                for (int cid : candCells) {\n                    ll val = 0;\n                    val += distAll[prevIdx][cid];\n                    val += distAll[nextIdx][cid] + sourceW[nextIdx] - cellW[cid];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestCid = cid;\n                    }\n                }\n                if (bestCid != tasks[ti].cell) {\n                    newCells[ti] = bestCid;\n                    changed = true;\n                }\n            }\n\n            if (changed) {\n                for (int i = 0; i < M; i++) tasks[i].cell = newCells[i];\n                continue;\n            }\n        }\n        break;\n    }\n\n    string path = reconstructPath(bestRoute, sourceCells, parentAll);\n    if (path.empty()) {\n        // empty is okay only if it really covers everything\n        auto [ok, c] = validateAndCost(path);\n        if (ok) {\n            res.valid = true;\n            res.cost = c;\n            res.path = path;\n        }\n        return res;\n    }\n\n    auto [ok, c] = validateAndCost(path);\n    if (ok) {\n        res.valid = true;\n        res.cost = c;\n        res.path = move(path);\n    }\n    return res;\n}\n\nstring buildFallbackDFSRoute() {\n    vector<char> vis(Rcnt, false);\n    string out;\n\n    vector<int> it(Rcnt, 0);\n    vector<int> st;\n    st.push_back(sId);\n    vis[sId] = true;\n\n    while (!st.empty()) {\n        int u = st.back();\n        if (it[u] == (int)nbrs[u].size()) {\n            st.pop_back();\n            if (!st.empty()) {\n                int p = st.back();\n                out.push_back(dirChar(u, p));\n            }\n            continue;\n        }\n        int v = nbrs[u][it[u]++];\n        if (vis[v]) continue;\n        vis[v] = true;\n        out.push_back(dirChar(u, v));\n        st.push_back(v);\n    }\n    return out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    globalStart = chrono::steady_clock::now();\n\n    cin >> N >> si >> sj;\n    gridc.resize(N);\n    for (int i = 0; i < N; i++) cin >> gridc[i];\n\n    idg.assign(N, vector<int>(N, -1));\n    rr.clear(); cc.clear(); cellW.clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (gridc[i][j] != '#') {\n                idg[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                cellW.push_back(gridc[i][j] - '0');\n            }\n        }\n    }\n    Rcnt = (int)rr.size();\n    sId = idg[si][sj];\n\n    nbrs.assign(Rcnt, {});\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int i = rr[cid], j = cc[cid];\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) {\n                int nid = idg[ni][nj];\n                if (nid != -1) nbrs[cid].push_back(nid);\n            }\n        }\n    }\n    for (int u = 0; u < Rcnt; u++) {\n        sort(nbrs[u].begin(), nbrs[u].end(), [&](int a, int b) {\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    hid.assign(Rcnt, -1);\n    vid.assign(Rcnt, -1);\n\n    Hcnt = 0;\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (idg[i][j] == -1) {\n                j++;\n                continue;\n            }\n            int h = Hcnt++;\n            cellsH.push_back({});\n            while (j < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                hid[cid] = h;\n                cellsH[h].push_back(cid);\n                j++;\n            }\n        }\n    }\n\n    Vcnt = 0;\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (idg[i][j] == -1) {\n                i++;\n                continue;\n            }\n            int v = Vcnt++;\n            cellsV.push_back({});\n            while (i < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                vid[cid] = v;\n                cellsV[v].push_back(cid);\n                i++;\n            }\n        }\n    }\n\n    adjHFull.assign(Hcnt, {});\n    for (int cid = 0; cid < Rcnt; cid++) {\n        adjHFull[hid[cid]].push_back({vid[cid], cid});\n    }\n\n    vector<int> dummyParent;\n    runDijkstra(sId, distStart, dummyParent);\n\n    bestCellH.assign(Hcnt, -1);\n    bestCellV.assign(Vcnt, -1);\n\n    auto betterCell = [&](int a, int b) {\n        if (a == -1) return true;\n        if (distStart[b] != distStart[a]) return distStart[b] < distStart[a];\n        if (cellW[b] != cellW[a]) return cellW[b] < cellW[a];\n        if (rr[b] != rr[a]) return rr[b] < rr[a];\n        return cc[b] < cc[a];\n    };\n\n    for (int h = 0; h < Hcnt; h++) {\n        for (int cid : cellsH[h]) {\n            if (bestCellH[h] == -1 || betterCell(bestCellH[h], cid)) {\n                bestCellH[h] = cid;\n            }\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        for (int cid : cellsV[v]) {\n            if (bestCellV[v] == -1 || betterCell(bestCellV[v], cid)) {\n                bestCellV[v] = cid;\n            }\n        }\n    }\n\n    for (int h = 0; h < Hcnt; h++) {\n        sort(adjHFull[h].begin(), adjHFull[h].end(), [&](auto A, auto B) {\n            int a = A.second, b = B.second;\n            if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    sH = hid[sId];\n    sV = vid[sId];\n\n    activeH.assign(Hcnt, false);\n    activeV.assign(Vcnt, false);\n    adjHRes.assign(Hcnt, {});\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int h = hid[cid], v = vid[cid];\n        if (h == sH || v == sV) continue; // already visible from start\n        activeH[h] = true;\n        activeV[v] = true;\n        adjHRes[h].push_back({v, cid});\n    }\n\n    vector<ll> segCostH(Hcnt, 0), segCostV(Vcnt, 0);\n    for (int h = 0; h < Hcnt; h++) segCostH[h] = distStart[bestCellH[h]];\n    for (int v = 0; v < Vcnt; v++) segCostV[v] = distStart[bestCellV[v]];\n\n    string bestPath = buildFallbackDFSRoute();\n    auto [fbok, fbcost] = validateAndCost(bestPath);\n    if (!fbok) {\n        bestPath = \"\";\n        fbcost = (1LL << 60);\n    }\n    ll bestCost = fbcost;\n\n    vector<pair<vector<char>, vector<char>>> candSets;\n\n    candSets.push_back(buildCanonicalMVC());\n\n    ll sumSeg = 0;\n    for (int h = 0; h < Hcnt; h++) if (activeH[h]) sumSeg += segCostH[h];\n    for (int v = 0; v < Vcnt; v++) if (activeV[v]) sumSeg += segCostV[v];\n    ll base = sumSeg + 1;\n\n    vector<ll> wH1(Hcnt, 0), wV1(Vcnt, 0);\n    vector<ll> wH2(Hcnt, 0), wV2(Vcnt, 0);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) {\n            wH1[h] = base + segCostH[h];\n            wH2[h] = 1 + segCostH[h];\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) {\n            wV1[v] = base + segCostV[v];\n            wV2[v] = 1 + segCostV[v];\n        }\n    }\n\n    candSets.push_back(buildWeightedVC(wH1, wV1));\n    candSets.push_back(buildWeightedVC(wH2, wV2));\n\n    vector<char> allH = activeH, allV = activeV;\n    candSets.push_back({allH, vector<char>(Vcnt, false)});\n    candSets.push_back({vector<char>(Hcnt, false), allV});\n\n    for (auto& [selH, selV] : candSets) {\n        if (elapsed_ms() > 2750) break;\n        vector<Task> tasks = buildTasksFromSelected(selH, selV);\n        CandidateResult cr = solveCandidate(tasks);\n        if (cr.valid && cr.cost < bestCost) {\n            bestCost = cr.cost;\n            bestPath = move(cr.path);\n        }\n    }\n\n    if (bestPath.empty()) {\n        // avoid zero-length tour if possible\n        if (!nbrs[sId].empty()) {\n            int v = nbrs[sId][0];\n            string tmp;\n            tmp.push_back(dirChar(sId, v));\n            tmp.push_back(dirChar(v, sId));\n            auto [ok, c] = validateAndCost(tmp);\n            if (ok) bestPath = tmp;\n        }\n    }\n\n    cout << bestPath << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int MAXN = 1000;\nstatic constexpr ll INF64 = (1LL << 62);\nstatic constexpr ll DUMMY_UTILITY = -4'000'000'000'000LL;\n\nstruct Observation {\n    int task;\n    int dur;\n};\n\nstruct Member {\n    int current_task = -1;\n    int start_day = -1;\n    vector<Observation> obs;\n    vector<int> est;\n    bool busy() const { return current_task != -1; }\n};\n\nstruct Solver {\n    int N, M, K, R;\n    vector<vector<int>> req;\n    vector<vector<int>> g;\n    vector<int> indeg_rem;\n    vector<int> state; // 0:not started, 1:in progress, 2:done\n    vector<Member> members;\n\n    vector<int> maxD;\n    vector<double> prior_cap;\n    vector<int> prior_int;\n    vector<double> rank_skill;\n    vector<double> easy_skill;\n\n    vector<int> desc_count;\n    vector<double> avg_proc;\n    vector<double> up_rank;\n    vector<double> base_priority_static;\n    vector<double> global_easy_dur;\n\n    int completed_tasks = 0;\n\n    static double expected_duration_from_w(double w) {\n        if (w <= 0.0) return 1.0;\n        static const double E[5] = {\n            1.0,\n            13.0 / 7.0,\n            17.0 / 7.0,\n            22.0 / 7.0,\n            4.0\n        };\n        if (w < 4.0) {\n            int a = (int)floor(w);\n            double f = w - a;\n            return E[a] * (1.0 - f) + E[a + 1] * f;\n        }\n        return w;\n    }\n\n    double predict_duration_with_skill(const vector<double>& skill, int task) const {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double diff = (double)req[task][k] - skill[k];\n            if (diff > 0) w += diff;\n        }\n        return expected_duration_from_w(w);\n    }\n\n    static pair<int,int> duration_interval(int t) {\n        if (t <= 1) return {0, 4};\n        return {max(1, t - 3), t + 3};\n    }\n\n    void read_input() {\n        cin >> N >> M >> K >> R;\n        req.assign(N, vector<int>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) cin >> req[i][k];\n        }\n        g.assign(N, {});\n        indeg_rem.assign(N, 0);\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            g[u].push_back(v);\n            indeg_rem[v]++;\n        }\n        state.assign(N, 0);\n        members.assign(M, Member{});\n    }\n\n    void preprocess() {\n        maxD.assign(K, 0);\n        vector<double> meanD(K, 0.0);\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                maxD[k] = max(maxD[k], req[i][k]);\n                meanD[k] += req[i][k];\n            }\n        }\n        for (int k = 0; k < K; k++) meanD[k] /= N;\n\n        prior_cap.assign(K, 0.0);\n        prior_int.assign(K, 0);\n        rank_skill.assign(K, 0.0);\n        easy_skill.assign(K, 0.0);\n\n        for (int k = 0; k < K; k++) {\n            double p = 1.6 * meanD[k];\n            p = min<double>(p, maxD[k]);\n            if (p < 0) p = 0;\n            prior_cap[k] = p;\n            prior_int[k] = (int)llround(p);\n            prior_int[k] = max(0, min(prior_int[k], maxD[k]));\n            rank_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.75);\n            easy_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.80);\n        }\n\n        for (int j = 0; j < M; j++) {\n            members[j].est = prior_int;\n        }\n\n        // Exact descendant counts with bitset.\n        vector<bitset<MAXN>> reach(N);\n        desc_count.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            bitset<MAXN> bs;\n            for (int to : g[i]) {\n                bs |= reach[to];\n                bs.set(to);\n            }\n            reach[i] = bs;\n            desc_count[i] = (int)bs.count();\n        }\n\n        avg_proc.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            avg_proc[i] = predict_duration_with_skill(rank_skill, i);\n        }\n\n        up_rank.assign(N, 0.0);\n        for (int i = N - 1; i >= 0; i--) {\n            double mx = 0.0;\n            for (int to : g[i]) mx = max(mx, up_rank[to]);\n            up_rank[i] = avg_proc[i] + mx;\n        }\n\n        base_priority_static.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            base_priority_static[i] = up_rank[i] + 0.03 * desc_count[i];\n        }\n\n        global_easy_dur.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            global_easy_dur[i] = predict_duration_with_skill(easy_skill, i);\n        }\n    }\n\n    void reestimate_member(int j) {\n        auto& mem = members[j];\n        int nobs = (int)mem.obs.size();\n        if (nobs == 0) {\n            mem.est = prior_int;\n            return;\n        }\n        if ((int)mem.est.size() != K) mem.est = prior_int;\n\n        vector<int> s = mem.est;\n        for (int k = 0; k < K; k++) {\n            s[k] = max(0, min(s[k], maxD[k]));\n        }\n\n        vector<int> task_id(nobs), L(nobs), U(nobs);\n        for (int i = 0; i < nobs; i++) {\n            task_id[i] = mem.obs[i].task;\n            auto [l, u] = duration_interval(mem.obs[i].dur);\n            L[i] = l;\n            U[i] = u;\n        }\n\n        vector<int> pred(nobs, 0);\n        for (int i = 0; i < nobs; i++) {\n            int t = task_id[i];\n            int w = 0;\n            for (int k = 0; k < K; k++) {\n                w += max(0, req[t][k] - s[k]);\n            }\n            pred[i] = w;\n        }\n\n        int passes = (nobs < 8 ? 3 : 2);\n        double reg = 10.0 / (nobs + 3.0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            for (int k = 0; k < K; k++) {\n                int old = s[k];\n                int lim = maxD[k];\n\n                vector<int> dk(nobs), oldPart(nobs);\n                for (int i = 0; i < nobs; i++) {\n                    int dkk = req[task_id[i]][k];\n                    dk[i] = dkk;\n                    oldPart[i] = max(0, dkk - old);\n                }\n\n                double bestObj = 1e100;\n                int bestX = old;\n\n                for (int x = 0; x <= lim; x++) {\n                    double obj = reg * (x - prior_int[k]) * (x - prior_int[k]);\n                    for (int i = 0; i < nobs; i++) {\n                        int w = pred[i] - oldPart[i] + max(0, dk[i] - x);\n                        if (w < L[i]) {\n                            double d = (double)(L[i] - w);\n                            obj += d * d;\n                        } else if (w > U[i]) {\n                            double d = (double)(w - U[i]);\n                            obj += d * d;\n                        }\n                    }\n                    if (obj < bestObj) {\n                        bestObj = obj;\n                        bestX = x;\n                    }\n                }\n\n                if (bestX != old) {\n                    for (int i = 0; i < nobs; i++) {\n                        pred[i] = pred[i] - oldPart[i] + max(0, dk[i] - bestX);\n                    }\n                    s[k] = bestX;\n                }\n            }\n        }\n\n        mem.est = s;\n    }\n\n    vector<int> hungarian_min(const vector<vector<ll>>& cost) {\n        int n = (int)cost.size();\n        int m = (int)cost[0].size();\n        // Requires n <= m\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF64);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF64;\n                for (int j = 1; j <= m; j++) {\n                    if (used[j]) continue;\n                    ll cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0 != 0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    vector<pair<int,int>> choose_assignments(int day) {\n        vector<int> free_members, ready_tasks;\n        for (int j = 0; j < M; j++) if (!members[j].busy()) free_members.push_back(j);\n        for (int i = 0; i < N; i++) if (state[i] == 0 && indeg_rem[i] == 0) ready_tasks.push_back(i);\n\n        if (free_members.empty() || ready_tasks.empty()) return {};\n\n        vector<vector<double>> eff_skill(M, vector<double>(K, 0.0));\n        for (int j = 0; j < M; j++) {\n            double conf = (double)members[j].obs.size() / (members[j].obs.size() + 5.0);\n            for (int k = 0; k < K; k++) {\n                eff_skill[j][k] = conf * members[j].est[k] + (1.0 - conf) * prior_cap[k];\n            }\n        }\n\n        vector<double> dynP(N, -1e100);\n        vector<pair<double,int>> order;\n        order.reserve(ready_tasks.size());\n\n        for (int task : ready_tasks) {\n            double unlock_bonus = 0.0;\n            for (int to : g[task]) {\n                if (state[to] == 0 && indeg_rem[to] == 1) {\n                    unlock_bonus += base_priority_static[to];\n                }\n            }\n            double p = base_priority_static[task] + 0.15 * unlock_bonus - 1e-4 * task;\n            dynP[task] = p;\n            order.push_back({p, task});\n        }\n\n        sort(order.begin(), order.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        auto raw_pred = [&](int member, int task) -> double {\n            return predict_duration_with_skill(eff_skill[member], task);\n        };\n\n        vector<char> used_member(M, false), used_task(N, false);\n        vector<pair<int,int>> res;\n\n        int urgent = 0;\n        if ((int)free_members.size() >= 2) {\n            urgent = min<int>((int)free_members.size(), (completed_tasks < 2 * M ? 2 : 3));\n        }\n\n        int ptr = 0;\n        while (urgent > 0 && ptr < (int)order.size()) {\n            int task = order[ptr++].second;\n            if (used_task[task]) continue;\n\n            double bestDur = 1e100;\n            int bestMember = -1;\n            for (int j : free_members) {\n                if (used_member[j]) continue;\n                double d = raw_pred(j, task);\n                if (d < bestDur - 1e-12 || (abs(d - bestDur) <= 1e-12 && j < bestMember)) {\n                    bestDur = d;\n                    bestMember = j;\n                }\n            }\n            if (bestMember == -1) break;\n\n            used_member[bestMember] = true;\n            used_task[task] = true;\n            res.push_back({bestMember, task});\n            urgent--;\n        }\n\n        vector<int> rem_members;\n        for (int j : free_members) if (!used_member[j]) rem_members.push_back(j);\n\n        vector<int> rem_tasks_order;\n        for (auto [p, t] : order) if (!used_task[t]) rem_tasks_order.push_back(t);\n\n        if (rem_members.empty() || rem_tasks_order.empty()) return res;\n\n        vector<int> cand;\n        vector<char> chosen(N, false);\n\n        if ((int)rem_tasks_order.size() <= 80) {\n            cand = rem_tasks_order;\n            for (int t : cand) chosen[t] = true;\n        } else {\n            const int TOP_PRIO = 50;\n            const int TOP_EASY = 25;\n\n            for (int i = 0; i < (int)rem_tasks_order.size() && (int)cand.size() < TOP_PRIO; i++) {\n                int t = rem_tasks_order[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            vector<int> easy = rem_tasks_order;\n            sort(easy.begin(), easy.end(), [&](int a, int b) {\n                if (global_easy_dur[a] != global_easy_dur[b]) return global_easy_dur[a] < global_easy_dur[b];\n                if (dynP[a] != dynP[b]) return dynP[a] > dynP[b];\n                return a < b;\n            });\n\n            for (int i = 0; i < (int)easy.size() && i < TOP_EASY; i++) {\n                int t = easy[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            int need = min<int>((int)rem_tasks_order.size(), max<int>((int)rem_members.size(), 20));\n            for (int t : rem_tasks_order) {\n                if ((int)cand.size() >= need) break;\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n        }\n\n        if (cand.empty()) return res;\n\n        int n = (int)rem_members.size();\n        int m = (int)cand.size() + n; // add dummy columns\n        vector<vector<ll>> util(n, vector<ll>(m, DUMMY_UTILITY));\n\n        for (int r = 0; r < n; r++) {\n            int member = rem_members[r];\n            int oc = (int)members[member].obs.size();\n            for (int c = 0; c < (int)cand.size(); c++) {\n                int task = cand[c];\n                double dur = raw_pred(member, task);\n\n                if (oc == 0) {\n                    if (completed_tasks < M) dur *= 2.2;\n                    else if (completed_tasks < 3 * M) dur *= 1.6;\n                } else if (oc == 1 && completed_tasks < 3 * M) {\n                    dur *= 1.2;\n                }\n\n                double u = dynP[task] * 1200.0 - dur * 800.0;\n                util[r][c] = llround(u);\n            }\n        }\n\n        ll maxU = DUMMY_UTILITY;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                maxU = max(maxU, util[i][j]);\n            }\n        }\n\n        vector<vector<ll>> cost(n, vector<ll>(m));\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                cost[i][j] = maxU - util[i][j];\n            }\n        }\n\n        vector<int> assign = hungarian_min(cost);\n        for (int r = 0; r < n; r++) {\n            int c = assign[r];\n            if (0 <= c && c < (int)cand.size()) {\n                res.push_back({rem_members[r], cand[c]});\n            }\n        }\n\n        return res;\n    }\n\n    void run() {\n        read_input();\n        preprocess();\n\n        for (int day = 1; ; day++) {\n            auto assignments = choose_assignments(day);\n\n            // Apply assignments locally before output.\n            for (auto [j, t] : assignments) {\n                members[j].current_task = t;\n                members[j].start_day = day;\n                state[t] = 1;\n            }\n\n            cout << assignments.size();\n            for (auto [j, t] : assignments) {\n                cout << ' ' << (j + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int ncomp;\n            if (!(cin >> ncomp)) return;\n            if (ncomp == -1) return;\n\n            vector<int> finished_members(ncomp);\n            for (int i = 0; i < ncomp; i++) {\n                cin >> finished_members[i];\n                --finished_members[i];\n            }\n\n            vector<int> completed_today_tasks;\n            completed_today_tasks.reserve(ncomp);\n\n            for (int j : finished_members) {\n                if (j < 0 || j >= M) continue;\n                if (!members[j].busy()) continue;\n\n                int task = members[j].current_task;\n                int dur = day - members[j].start_day + 1;\n\n                members[j].obs.push_back({task, dur});\n                members[j].current_task = -1;\n                members[j].start_day = -1;\n\n                if (0 <= task && task < N && state[task] == 1) {\n                    state[task] = 2;\n                    completed_today_tasks.push_back(task);\n                    completed_tasks++;\n                }\n\n                reestimate_member(j);\n            }\n\n            for (int task : completed_today_tasks) {\n                for (int to : g[task]) {\n                    if (state[to] == 0) {\n                        indeg_rem[to]--;\n                    }\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int N = 1000;\nstatic constexpr int M = 50;\nstatic constexpr int DEPOT_X = 400;\nstatic constexpr int DEPOT_Y = 400;\nstatic constexpr int MAX_ROUTE = 105;\nstatic constexpr ll INF64 = (1LL << 60);\n\nstruct Order {\n    int a, b, c, d; // restaurant (a,b), destination (c,d)\n};\n\nstruct Node {\n    int oid;      // -1 for depot\n    bool pickup;  // true: restaurant, false: destination\n    int x, y;\n};\n\nstruct Insertion {\n    ll delta;\n    int gapP;      // pickup inserted in gap gapP\n    int gapD;      // delivery inserted in gap gapD (if sameGap=false, gapD > gapP)\n    bool sameGap;  // delivery inserted right after pickup in same original gap\n};\n\nstruct Candidate {\n    ll delta;\n    int oid;\n    Insertion ins;\n};\n\nstruct RouteContext {\n    int L = 0;                 // number of nodes in route\n    int E = 0;                 // number of gaps = L - 1\n    int xs[MAX_ROUTE];\n    int ys[MAX_ROUTE];\n    int edge[MAX_ROUTE];\n    ll total = 0;\n};\n\nstruct Solution {\n    vector<Node> route;        // includes start/end depot\n    vector<char> selected;     // size N\n    ll cost = INF64;\n};\n\nchrono::steady_clock::time_point g_start;\nvector<Order> orders;\n\ninline int md(int x1, int y1, int x2, int y2) {\n    return abs(x1 - x2) + abs(y1 - y2);\n}\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nNode depot_node() {\n    return Node{-1, false, DEPOT_X, DEPOT_Y};\n}\n\nNode pickup_node(int oid) {\n    return Node{oid, true, orders[oid].a, orders[oid].b};\n}\n\nNode delivery_node(int oid) {\n    return Node{oid, false, orders[oid].c, orders[oid].d};\n}\n\nll calc_cost(const vector<Node>& route) {\n    ll res = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        res += md(route[i].x, route[i].y, route[i + 1].x, route[i + 1].y);\n    }\n    return res;\n}\n\nRouteContext build_context(const vector<Node>& route) {\n    RouteContext ctx;\n    ctx.L = (int)route.size();\n    ctx.E = ctx.L - 1;\n    ctx.total = 0;\n    for (int i = 0; i < ctx.L; i++) {\n        ctx.xs[i] = route[i].x;\n        ctx.ys[i] = route[i].y;\n    }\n    for (int i = 0; i < ctx.E; i++) {\n        ctx.edge[i] = md(ctx.xs[i], ctx.ys[i], ctx.xs[i + 1], ctx.ys[i + 1]);\n        ctx.total += ctx.edge[i];\n    }\n    return ctx;\n}\n\n// O(route length) best feasible insertion for one order.\nInsertion find_best_insertion(const RouteContext& ctx, int oid) {\n    const int px = orders[oid].a;\n    const int py = orders[oid].b;\n    const int dx = orders[oid].c;\n    const int dy = orders[oid].d;\n    const int pd = md(px, py, dx, dy);\n\n    ll delCost[MAX_ROUTE];\n    ll suffMin[MAX_ROUTE];\n    int suffArg[MAX_ROUTE];\n\n    for (int j = 0; j < ctx.E; j++) {\n        delCost[j] =\n            (ll)md(ctx.xs[j], ctx.ys[j], dx, dy) +\n            (ll)md(dx, dy, ctx.xs[j + 1], ctx.ys[j + 1]) -\n            (ll)ctx.edge[j];\n    }\n\n    suffMin[ctx.E] = INF64;\n    suffArg[ctx.E] = -1;\n    for (int j = ctx.E - 1; j >= 0; j--) {\n        if (delCost[j] <= suffMin[j + 1]) {\n            suffMin[j] = delCost[j];\n            suffArg[j] = j;\n        } else {\n            suffMin[j] = suffMin[j + 1];\n            suffArg[j] = suffArg[j + 1];\n        }\n    }\n\n    Insertion best{INF64, -1, -1, true};\n\n    for (int i = 0; i < ctx.E; i++) {\n        const int x1 = ctx.xs[i];\n        const int y1 = ctx.ys[i];\n        const int x2 = ctx.xs[i + 1];\n        const int y2 = ctx.ys[i + 1];\n        const int base = ctx.edge[i];\n\n        // delivery inserted right after pickup in the same original gap\n        ll same =\n            (ll)md(x1, y1, px, py) +\n            (ll)pd +\n            (ll)md(dx, dy, x2, y2) -\n            (ll)base;\n        if (same < best.delta) {\n            best = Insertion{same, i, i, true};\n        }\n\n        // delivery inserted in a later gap\n        if (i + 1 < ctx.E) {\n            ll pickCost =\n                (ll)md(x1, y1, px, py) +\n                (ll)md(px, py, x2, y2) -\n                (ll)base;\n            ll later = pickCost + suffMin[i + 1];\n            if (later < best.delta) {\n                best = Insertion{later, i, suffArg[i + 1], false};\n            }\n        }\n    }\n\n    return best;\n}\n\nvector<Node> apply_insertion(const vector<Node>& route, int oid, const Insertion& ins) {\n    vector<Node> res = route;\n    res.reserve(route.size() + 2);\n\n    Node p = pickup_node(oid);\n    Node d = delivery_node(oid);\n\n    if (ins.sameGap) {\n        res.insert(res.begin() + (ins.gapP + 1), p);\n        res.insert(res.begin() + (ins.gapP + 2), d);\n    } else {\n        // Insert delivery first (in original gap gapD), then pickup.\n        res.insert(res.begin() + (ins.gapD + 1), d);\n        res.insert(res.begin() + (ins.gapP + 1), p);\n    }\n    return res;\n}\n\nvector<Node> remove_order_from_route(const vector<Node>& route, int oid) {\n    vector<Node> res;\n    res.reserve(route.size() - 2);\n    for (const auto& nd : route) {\n        if (nd.oid != oid) res.push_back(nd);\n    }\n    return res;\n}\n\nvoid add_candidate(vector<Candidate>& bests, const Candidate& c, int K) {\n    auto it = bests.begin();\n    while (it != bests.end() && it->delta <= c.delta) ++it;\n\n    if ((int)bests.size() < K) {\n        bests.insert(it, c);\n    } else if (it != bests.end()) {\n        bests.insert(it, c);\n        bests.pop_back();\n    }\n}\n\nint choose_candidate_index(const vector<Candidate>& bests, mt19937& rng, bool randomized) {\n    if (!randomized || bests.size() <= 1) return 0;\n    if (bests.size() == 2) {\n        static const int w2[2] = {75, 25};\n        discrete_distribution<int> dist(w2, w2 + 2);\n        return dist(rng);\n    } else {\n        static const int w3[3] = {60, 25, 15};\n        discrete_distribution<int> dist(w3, w3 + 3);\n        return dist(rng);\n    }\n}\n\n// Construct a solution by greedy pair insertion.\n// If seedOid != -1, that order is forced to be the first chosen one.\nSolution construct_solution(int seedOid, bool randomized, mt19937& rng) {\n    Solution sol;\n    sol.route = {depot_node(), depot_node()};\n    sol.selected.assign(N, 0);\n    sol.cost = 0;\n\n    int chosen = 0;\n    if (seedOid != -1) {\n        Insertion first{\n            (ll)md(DEPOT_X, DEPOT_Y, orders[seedOid].a, orders[seedOid].b) +\n            (ll)md(orders[seedOid].a, orders[seedOid].b, orders[seedOid].c, orders[seedOid].d) +\n            (ll)md(orders[seedOid].c, orders[seedOid].d, DEPOT_X, DEPOT_Y),\n            0, 0, true\n        };\n        sol.route = apply_insertion(sol.route, seedOid, first);\n        sol.selected[seedOid] = 1;\n        sol.cost = calc_cost(sol.route);\n        chosen = 1;\n    }\n\n    for (int step = chosen; step < M; step++) {\n        RouteContext ctx = build_context(sol.route);\n        int K = randomized ? 3 : 1;\n        vector<Candidate> bests;\n        bests.reserve(K);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.selected[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, K);\n        }\n\n        int idx = choose_candidate_index(bests, rng, randomized);\n        const auto& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.selected[c.oid] = 1;\n        sol.cost = calc_cost(sol.route);\n    }\n\n    return sol;\n}\n\nbool pair_reinsert_sweep(Solution& sol, mt19937& rng) {\n    vector<int> sel;\n    sel.reserve(M);\n    for (int i = 0; i < N; i++) if (sol.selected[i]) sel.push_back(i);\n    shuffle(sel.begin(), sel.end(), rng);\n\n    bool improved = false;\n\n    for (int oid : sel) {\n        vector<Node> base = remove_order_from_route(sol.route, oid);\n        RouteContext ctx = build_context(base);\n        Insertion ins = find_best_insertion(ctx, oid);\n        ll predicted = ctx.total + ins.delta;\n        if (predicted >= sol.cost) continue;\n\n        vector<Node> nr = apply_insertion(base, oid, ins);\n        ll realCost = calc_cost(nr);\n        if (realCost < sol.cost) {\n            sol.route = move(nr);\n            sol.cost = realCost;\n            improved = true;\n        }\n    }\n\n    return improved;\n}\n\nbool pair_replace_best(Solution& sol, double deadline_sec) {\n    vector<int> sel, unsel;\n    sel.reserve(M);\n    unsel.reserve(N - M);\n    for (int i = 0; i < N; i++) {\n        if (sol.selected[i]) sel.push_back(i);\n        else unsel.push_back(i);\n    }\n\n    ll bestCost = sol.cost;\n    int remOid = -1, addOid = -1;\n    Insertion bestIns{};\n    vector<Node> bestBase;\n\n    for (int si = 0; si < (int)sel.size(); si++) {\n        if ((si & 3) == 0 && elapsed_sec() > deadline_sec) break;\n\n        int x = sel[si];\n        vector<Node> base = remove_order_from_route(sol.route, x);\n        RouteContext ctx = build_context(base);\n\n        ll bestDelta = INF64;\n        int bestY = -1;\n        Insertion bestYIns{};\n\n        for (int y : unsel) {\n            Insertion ins = find_best_insertion(ctx, y);\n            if (ins.delta < bestDelta) {\n                bestDelta = ins.delta;\n                bestY = y;\n                bestYIns = ins;\n            }\n        }\n\n        ll predicted = ctx.total + bestDelta;\n        if (predicted < bestCost) {\n            bestCost = predicted;\n            remOid = x;\n            addOid = bestY;\n            bestIns = bestYIns;\n            bestBase = move(base);\n        }\n    }\n\n    if (remOid == -1) return false;\n\n    vector<Node> nr = apply_insertion(bestBase, addOid, bestIns);\n    ll realCost = calc_cost(nr);\n    if (realCost >= sol.cost) return false;\n\n    sol.selected[remOid] = 0;\n    sol.selected[addOid] = 1;\n    sol.route = move(nr);\n    sol.cost = realCost;\n    return true;\n}\n\nvoid improve_solution(Solution& sol, mt19937& rng, int maxOuter, double deadline_sec) {\n    for (int outer = 0; outer < maxOuter; outer++) {\n        if (elapsed_sec() > deadline_sec) break;\n        bool any = false;\n\n        for (int sweep = 0; sweep < 3; sweep++) {\n            if (elapsed_sec() > deadline_sec) break;\n            bool ch = pair_reinsert_sweep(sol, rng);\n            any |= ch;\n            if (!ch) break;\n        }\n\n        if (elapsed_sec() > deadline_sec) break;\n        bool rep = pair_replace_best(sol, deadline_sec);\n        any |= rep;\n\n        if (!any) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    orders.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> orders[i].a >> orders[i].b >> orders[i].c >> orders[i].d;\n    }\n\n    g_start = chrono::steady_clock::now();\n    mt19937 rng(123456789);\n\n    vector<pair<int, int>> centerRank;\n    centerRank.reserve(N);\n    for (int i = 0; i < N; i++) {\n        ll cc =\n            (ll)md(DEPOT_X, DEPOT_Y, orders[i].a, orders[i].b) +\n            (ll)md(orders[i].a, orders[i].b, orders[i].c, orders[i].d) +\n            (ll)md(orders[i].c, orders[i].d, DEPOT_X, DEPOT_Y);\n        centerRank.push_back({(int)cc, i});\n    }\n    sort(centerRank.begin(), centerRank.end());\n\n    vector<int> seedPool;\n    for (int i = 0; i < min(200, N); i++) seedPool.push_back(centerRank[i].second);\n\n    Solution best;\n    bool hasBest = false;\n\n    // A few deterministic initial runs.\n    vector<int> initialSeeds = {-1};\n    for (int i = 0; i < 3; i++) initialSeeds.push_back(centerRank[i].second);\n\n    for (int seed : initialSeeds) {\n        if (elapsed_sec() > 0.9) break;\n        Solution cur = construct_solution(seed, false, rng);\n        improve_solution(cur, rng, 4, 1.55);\n        if (!hasBest || cur.cost < best.cost) {\n            best = move(cur);\n            hasBest = true;\n        }\n    }\n\n    // One randomized run without a forced seed.\n    if (elapsed_sec() <= 1.1) {\n        Solution cur = construct_solution(-1, true, rng);\n        improve_solution(cur, rng, 4, 1.55);\n        if (!hasBest || cur.cost < best.cost) {\n            best = move(cur);\n            hasBest = true;\n        }\n    }\n\n    // Multistart randomized runs.\n    while (elapsed_sec() < 1.55) {\n        int seed = ((rng() & 3) == 0 ? -1 : seedPool[rng() % seedPool.size()]);\n        Solution cur = construct_solution(seed, true, rng);\n        improve_solution(cur, rng, 2, 1.55);\n        if (!hasBest || cur.cost < best.cost) {\n            best = move(cur);\n            hasBest = true;\n        }\n    }\n\n    // Final intensification.\n    improve_solution(best, rng, 100, 1.92);\n\n    // Output selected order IDs from the route (pickup nodes).\n    vector<int> ids;\n    vector<char> seen(N, 0);\n    for (const auto& nd : best.route) {\n        if (nd.oid >= 0 && nd.pickup && !seen[nd.oid]) {\n            seen[nd.oid] = 1;\n            ids.push_back(nd.oid + 1); // 1-indexed\n        }\n    }\n\n    cout << ids.size();\n    for (int id : ids) cout << ' ' << id;\n    cout << '\\n';\n\n    cout << best.route.size();\n    for (const auto& nd : best.route) {\n        cout << ' ' << nd.x << ' ' << nd.y;\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p; // negative size for root\n    DSU() {}\n    DSU(int n) : p(n, -1) {}\n\n    int leader(int x) {\n        if (p[x] < 0) return x;\n        return p[x] = leader(p[x]);\n    }\n\n    bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (-p[a] < -p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        return true;\n    }\n\n    int size(int x) {\n        return -p[leader(x)];\n    }\n};\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> xs[i] >> ys[i];\n    }\n\n    vector<int> U(M), V(M), D(M);\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n        long long dx = xs[U[i]] - xs[V[i]];\n        long long dy = ys[U[i]] - ys[V[i]];\n        D[i] = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n    }\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    DSU adopted(N);\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        // If already connected by adopted edges, taking this edge can only add useless cycle cost.\n        if (!adopted.same(u, v)) {\n            // Compress current adopted components to 0..C-1\n            vector<int> root_id(N, -1), cid(N, -1);\n            int C = 0;\n            for (int x = 0; x < N; x++) {\n                int r = adopted.leader(x);\n                if (root_id[r] == -1) root_id[r] = C++;\n                cid[x] = root_id[r];\n            }\n\n            int cu = cid[u], cv = cid[v];\n\n            // Build future-only MST on current components, using D as predicted weight.\n            DSU uf2(C);\n            vector<vector<pair<int,int>>> tree(C); // (to, d)\n            int used = 0;\n            int useful_edges = 0;\n\n            for (int e : ord) {\n                if (e <= i) continue; // only unseen future edges\n\n                int a = cid[U[e]];\n                int b = cid[V[e]];\n                if (a == b) continue;\n\n                useful_edges++;\n                if (uf2.merge(a, b)) {\n                    tree[a].push_back({b, D[e]});\n                    tree[b].push_back({a, D[e]});\n                    used++;\n                }\n            }\n\n            // If future edges alone cannot connect the current components, this edge is mandatory.\n            if (used < C - 1) {\n                ans = 1;\n            } else {\n                // Find max D on the path between cu and cv in the future-only MST.\n                vector<int> parent(C, -1), pw(C, 0);\n                queue<int> q;\n                parent[cu] = cu;\n                q.push(cu);\n\n                while (!q.empty() && parent[cv] == -1) {\n                    int x = q.front();\n                    q.pop();\n                    for (auto [to, w] : tree[x]) {\n                        if (parent[to] != -1) continue;\n                        parent[to] = x;\n                        pw[to] = w;\n                        q.push(to);\n                    }\n                }\n\n                int mx = 0;\n                for (int cur = cv; cur != cu; cur = parent[cur]) {\n                    mx = max(mx, pw[cur]);\n                }\n\n                // Dynamic threshold:\n                // more future alternatives => smaller lambda\n                // fewer future alternatives => larger lambda\n                double density = (C <= 1 ? 10.0 : (double)useful_edges / (double)(C - 1));\n                double t = (density - 1.0) / 4.0; // around 0 when density~1, 1 when density~5\n                if (t < 0.0) t = 0.0;\n                if (t > 1.0) t = 1.0;\n\n                double lambda = 2.05 - 0.45 * t; // from 2.05 down to 1.60\n\n                if ((double)l <= lambda * (double)mx + 1e-9) {\n                    ans = 1;\n                } else {\n                    ans = 0;\n                }\n            }\n        } else {\n            ans = 0;\n        }\n\n        cout << ans << '\\n' << flush;\n        if (ans) adopted.merge(u, v);\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int S = 30;\nstatic constexpr int MAX_TURN = 300;\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar moveChar[4] = {'U', 'D', 'L', 'R'};\nchar buildCharLower[4] = {'u', 'd', 'l', 'r'};\n\nstruct Task {\n    int wr, wc;   // wall cell to block\n    int sr, sc;   // stance cell to stand on\n    char act;     // build action\n};\n\nstruct Room {\n    int r1, r2, c1, c2;      // inside rectangle inclusive\n    int br, bc;              // horizontal/vertical barrier lines\n    int doorR, doorC;        // the last door cell to close\n    int inDoorR, inDoorC;    // inside-adjacent cell for closing the door\n    int centerR, centerC;    // room center\n    char doorAct;            // action to close the door\n    vector<Task> tasks;      // all wall cells except the final door\n\n    bool inside(int r, int c) const {\n        return r1 <= r && r <= r2 && c1 <= c && c <= c2;\n    }\n    int area() const {\n        return (r2 - r1 + 1) * (c2 - c1 + 1);\n    }\n};\n\nstruct BFSRes {\n    int dist[S][S];\n    char first[S][S];\n    BFSRes() {\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < S; j++) {\n                dist[i][j] = -1;\n                first[i][j] = 0;\n            }\n        }\n    }\n};\n\nint N, M;\nvector<pair<int,int>> petsPos;\nvector<int> petsType;\nvector<pair<int,int>> humansPos;\n\narray<array<bool, S>, S> wallCell;\n\ninline bool inb(int r, int c) {\n    return 0 <= r && r < S && 0 <= c && c < S;\n}\n\npair<int,int> apply_dir(pair<int,int> p, char ch) {\n    if (ch == 'U' || ch == 'u') return {p.first - 1, p.second};\n    if (ch == 'D' || ch == 'd') return {p.first + 1, p.second};\n    if (ch == 'L' || ch == 'l') return {p.first, p.second - 1};\n    if (ch == 'R' || ch == 'r') return {p.first, p.second + 1};\n    return p;\n}\n\nRoom make_room(int corner, int H, int W) {\n    // corner: 0 TL, 1 TR, 2 BL, 3 BR\n    bool top = (corner == 0 || corner == 1);\n    bool left = (corner == 0 || corner == 2);\n\n    Room room;\n    if (top) {\n        room.r1 = 0;\n        room.r2 = H - 1;\n        room.br = H;\n        room.inDoorR = H - 1;\n        room.doorAct = 'd';\n    } else {\n        room.r1 = S - H;\n        room.r2 = S - 1;\n        room.br = S - H - 1;\n        room.inDoorR = S - H;\n        room.doorAct = 'u';\n    }\n\n    if (left) {\n        room.c1 = 0;\n        room.c2 = W - 1;\n        room.bc = W;\n    } else {\n        room.c1 = S - W;\n        room.c2 = S - 1;\n        room.bc = S - W - 1;\n    }\n\n    room.doorC = (room.c1 + room.c2) / 2;\n    room.doorR = room.br;\n    room.inDoorC = room.doorC;\n    room.centerR = (room.r1 + room.r2) / 2;\n    room.centerC = (room.c1 + room.c2) / 2;\n\n    room.tasks.clear();\n\n    // Horizontal barrier except the door\n    for (int c = room.c1; c <= room.c2; c++) {\n        if (c == room.doorC) continue;\n        Task t;\n        t.wr = room.br; t.wc = c;\n        t.sr = room.inDoorR; t.sc = c;\n        t.act = room.doorAct;\n        room.tasks.push_back(t);\n    }\n\n    // Vertical barrier\n    int insideCol = left ? room.c2 : room.c1;\n    char vAct = left ? 'r' : 'l';\n    for (int r = room.r1; r <= room.r2; r++) {\n        Task t;\n        t.wr = r; t.wc = room.bc;\n        t.sr = r; t.sc = insideCol;\n        t.act = vAct;\n        room.tasks.push_back(t);\n    }\n\n    return room;\n}\n\nint dist_to_rect(const Room& room, int r, int c) {\n    int vr = 0, vc = 0;\n    if (r < room.r1) vr = room.r1 - r;\n    else if (r > room.r2) vr = r - room.r2;\n    if (c < room.c1) vc = room.c1 - c;\n    else if (c > room.c2) vc = c - room.c2;\n    return vr + vc;\n}\n\nRoom choose_room() {\n    vector<pair<int,int>> cand = {\n        {8, 8}, {8, 10}, {10, 8}, {10, 10},\n        {10, 12}, {12, 10}, {12, 12}, {12, 14}, {14, 12}\n    };\n\n    double bestScore = -1e100;\n    Room bestRoom = make_room(0, 10, 10);\n\n    for (auto [H, W] : cand) {\n        for (int corner = 0; corner < 4; corner++) {\n            Room room = make_room(corner, H, W);\n\n            int insidePets = 0;\n            int insideDogs = 0;\n            for (int i = 0; i < N; i++) {\n                auto [r, c] = petsPos[i];\n                if (room.inside(r, c)) {\n                    insidePets++;\n                    if (petsType[i] == 4) insideDogs++;\n                }\n            }\n\n            int sumDist = 0;\n            for (int i = 0; i < M; i++) {\n                auto [r, c] = humansPos[i];\n                sumDist += dist_to_rect(room, r, c);\n            }\n\n            // Heuristic:\n            // larger area is good, but pets/dogs inside are heavily bad.\n            double score = room.area();\n            score *= pow(0.6, insidePets);\n            score *= pow(0.6, insideDogs);\n            score -= 0.15 * sumDist;\n\n            if (score > bestScore) {\n                bestScore = score;\n                bestRoom = room;\n            }\n        }\n    }\n    return bestRoom;\n}\n\nBFSRes bfs_from(pair<int,int> st, const array<array<bool, S>, S>& blocked) {\n    BFSRes res;\n    queue<pair<int,int>> q;\n    auto [sr, sc] = st;\n    res.dist[sr][sc] = 0;\n    res.first[sr][sc] = '.';\n    q.push(st);\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n        for (int k = 0; k < 4; k++) {\n            int nr = r + dr[k], nc = c + dc[k];\n            if (!inb(nr, nc)) continue;\n            if (blocked[nr][nc]) continue;\n            if (res.dist[nr][nc] != -1) continue;\n            res.dist[nr][nc] = res.dist[r][c] + 1;\n            res.first[nr][nc] = (res.dist[r][c] == 0 ? moveChar[k] : res.first[r][c]);\n            q.push({nr, nc});\n        }\n    }\n    return res;\n}\n\nbool can_block_cell(int tr, int tc,\n                    const array<array<int, S>, S>& humanCnt,\n                    const array<array<int, S>, S>& petCnt) {\n    if (!inb(tr, tc)) return false;\n    if (humanCnt[tr][tc] > 0) return false;\n    if (petCnt[tr][tc] > 0) return false;\n    for (int k = 0; k < 4; k++) {\n        int nr = tr + dr[k], nc = tc + dc[k];\n        if (!inb(nr, nc)) continue;\n        if (petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nvoid rebuild_counts(array<array<int, S>, S>& humanCnt,\n                    array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            humanCnt[i][j] = 0;\n            petCnt[i][j] = 0;\n        }\n    }\n    for (auto [r, c] : humansPos) humanCnt[r][c]++;\n    for (auto [r, c] : petsPos) petCnt[r][c]++;\n}\n\nbool all_humans_inside(const Room& room) {\n    for (auto [r, c] : humansPos) {\n        if (!room.inside(r, c)) return false;\n    }\n    return true;\n}\n\nint pets_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : petsPos) {\n        if (room.inside(r, c)) cnt++;\n    }\n    return cnt;\n}\n\nbool unfinished_exists(const Room& room) {\n    for (auto &t : room.tasks) {\n        if (!wallCell[t.wr][t.wc]) return true;\n    }\n    return false;\n}\n\nbool should_close_now(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 240 && petsInside <= 1) return true;\n    if (turn >= 270 && petsInside <= 2) return true;\n    if (turn >= 290 && petsInside <= 3) return true;\n    if (turn >= 298) return true;\n    return false;\n}\n\nstring plan_build_actions(const Room& room,\n                          const array<array<int, S>, S>& humanCnt,\n                          const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n\n    vector<int> unfinished;\n    for (int i = 0; i < (int)room.tasks.size(); i++) {\n        auto &t = room.tasks[i];\n        if (!wallCell[t.wr][t.wc]) unfinished.push_back(i);\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    vector<bool> humanUsed(M, false);\n    vector<bool> taskUsed(room.tasks.size(), false);\n\n    // First: if already on a stance and legal, build immediately.\n    for (int i = 0; i < M; i++) {\n        auto [hr, hc] = humansPos[i];\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                if (can_block_cell(t.wr, t.wc, humanCnt, petCnt) && !toBlock[t.wr][t.wc]) {\n                    act[i] = t.act;\n                    humanUsed[i] = true;\n                    taskUsed[idx] = true;\n                    toBlock[t.wr][t.wc] = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    array<array<bool, S>, S> blocked = wallCell;\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) blocked[i][j] = true;\n        }\n    }\n\n    vector<BFSRes> bfsRes(M);\n    for (int i = 0; i < M; i++) {\n        if (!humanUsed[i]) bfsRes[i] = bfs_from(humansPos[i], blocked);\n    }\n\n    vector<int> assignedTask(M, -1);\n\n    // Greedy matching: nearest human -> unfinished task\n    while (true) {\n        int bestH = -1, bestT = -1, bestD = 1e9;\n        for (int i = 0; i < M; i++) {\n            if (humanUsed[i]) continue;\n            for (int idx : unfinished) {\n                if (taskUsed[idx]) continue;\n                auto &t = room.tasks[idx];\n                int d = bfsRes[i].dist[t.sr][t.sc];\n                if (d <= 0) continue; // exclude unreachable / already on stance (but not buildable)\n                if (d < bestD) {\n                    bestD = d;\n                    bestH = i;\n                    bestT = idx;\n                }\n            }\n        }\n        if (bestH == -1) break;\n        humanUsed[bestH] = true;\n        taskUsed[bestT] = true;\n        assignedTask[bestH] = bestT;\n    }\n\n    // Moves for assigned humans\n    for (int i = 0; i < M; i++) {\n        if (assignedTask[i] != -1) {\n            auto &t = room.tasks[assignedTask[i]];\n            char mv = bfsRes[i].first[t.sr][t.sc];\n            if (mv) act[i] = mv;\n        }\n    }\n\n    // Fallback for still-idle humans\n    for (int i = 0; i < M; i++) {\n        if (act[i] != '.') continue;\n\n        auto [hr, hc] = humansPos[i];\n        bool onSomeUnfinishedStance = false;\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                onSomeUnfinishedStance = true;\n                break;\n            }\n        }\n        if (onSomeUnfinishedStance) continue; // stay and wait\n\n        BFSRes b = bfs_from(humansPos[i], blocked);\n        int d = b.dist[room.centerR][room.centerC];\n        if (d > 0) act[i] = b.first[room.centerR][room.centerC];\n    }\n\n    return act;\n}\n\nstring plan_wait_actions(const Room& room, int turn,\n                         const array<array<int, S>, S>& humanCnt,\n                         const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n\n    int petsInside = pets_inside_count(room);\n    bool allInside = all_humans_inside(room);\n\n    // If possible, close now.\n    if (allInside && should_close_now(turn, petsInside) &&\n        can_block_cell(room.doorR, room.doorC, humanCnt, petCnt)) {\n        for (int i = 0; i < M; i++) {\n            auto [r, c] = humansPos[i];\n            if (r == room.inDoorR && c == room.inDoorC) {\n                act[i] = room.doorAct;\n                return act;\n            }\n        }\n    }\n\n    // Otherwise move humans.\n    array<array<bool, S>, S> blocked = wallCell;\n    vector<BFSRes> bfsRes(M);\n    for (int i = 0; i < M; i++) bfsRes[i] = bfs_from(humansPos[i], blocked);\n\n    bool wantLeaderAtDoor = (petsInside == 0) || (turn >= 220);\n    int leader = -1;\n    if (wantLeaderAtDoor) {\n        int best = 1e9;\n        for (int i = 0; i < M; i++) {\n            int d = bfsRes[i].dist[room.inDoorR][room.inDoorC];\n            if (d >= 0 && d < best) {\n                best = d;\n                leader = i;\n            }\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        int tr = room.centerR, tc = room.centerC;\n        if (i == leader) {\n            tr = room.inDoorR;\n            tc = room.inDoorC;\n        }\n        int d = bfsRes[i].dist[tr][tc];\n        if (d > 0) {\n            act[i] = bfsRes[i].first[tr][tc];\n        }\n    }\n\n    return act;\n}\n\nvoid apply_human_actions(const string& act) {\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    // Determine blocked cells\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if ('a' <= a && a <= 'z') {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc)) toBlock[nr][nc] = true;\n        }\n    }\n\n    // Build walls first\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) wallCell[i][j] = true;\n        }\n    }\n\n    // Then move humans\n    vector<pair<int,int>> newHumans = humansPos;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if ('A' <= a && a <= 'Z') {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc) && !wallCell[nr][nc]) {\n                newHumans[i] = {nr, nc};\n            }\n        }\n    }\n    humansPos.swap(newHumans);\n}\n\nvoid apply_pet_moves(const vector<string>& petMoves) {\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        for (char ch : petMoves[i]) {\n            if (ch == '.') continue;\n            auto [nr, nc] = apply_dir({r, c}, ch);\n            r = nr; c = nc;\n        }\n        petsPos[i] = {r, c};\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    petsPos.resize(N);\n    petsType.resize(N);\n    for (int i = 0; i < N; i++) {\n        int x, y, t;\n        cin >> x >> y >> t;\n        --x; --y;\n        petsPos[i] = {x, y};\n        petsType[i] = t;\n    }\n\n    cin >> M;\n    humansPos.resize(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        --x; --y;\n        humansPos[i] = {x, y};\n    }\n\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) wallCell[i][j] = false;\n\n    Room room = choose_room();\n\n    for (int turn = 0; turn < MAX_TURN; turn++) {\n        array<array<int, S>, S> humanCnt, petCnt;\n        rebuild_counts(humanCnt, petCnt);\n\n        string act(M, '.');\n\n        bool doorClosed = wallCell[room.doorR][room.doorC];\n        if (doorClosed) {\n            act = string(M, '.');\n        } else if (unfinished_exists(room)) {\n            act = plan_build_actions(room, humanCnt, petCnt);\n        } else {\n            act = plan_wait_actions(room, turn, humanCnt, petCnt);\n        }\n\n        cout << act << '\\n' << flush;\n\n        apply_human_actions(act);\n\n        vector<string> petMoves(N);\n        for (int i = 0; i < N; i++) {\n            if (!(cin >> petMoves[i])) return 0;\n        }\n        apply_pet_moves(petMoves);\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 20;\nconstexpr int V = N * N;\nconstexpr int LMAX = 200;\nconstexpr int NONE = 4;\n\nconst char ACT[4] = {'U', 'D', 'L', 'R'};\nconst int di[4] = {-1, 1, 0, 0};\nconst int dj[4] = {0, 0, -1, 1};\nconst int prefDirOrder[4] = {1, 3, 0, 2}; // D, R, U, L\nconst int isUL[4] = {1, 0, 1, 0};\n\nint si, sj, ti, tj, sid, tid;\ndouble p_forget, p_move;\n\nstring H[N];\nstring VW[N - 1];\n\nint toCell[V][4];\nunsigned char transKind[V][4]; // 0: stay, 1: move, 2: hit target\nvector<int> neighbors[V];\n\nint distToT[V];\nbool spValid[V][4];\n\ndouble hitReward[LMAX + 1];\ndouble UB[LMAX + 2][V];\n\ndouble preDist[LMAX + 1][V];\ndouble sufVal[LMAX + 2][V];\ndouble prefScore[LMAX + 1];\n\nint dpMinTurn[V][5];\nint dpMaxTurn[V][5];\n\ninline int ID(int i, int j) { return i * N + j; }\n\nvoid buildTransitions() {\n    for (int c = 0; c < V; c++) neighbors[c].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = ID(i, j);\n\n            // U\n            if (i > 0 && VW[i - 1][j] == '0') toCell[c][0] = ID(i - 1, j);\n            else toCell[c][0] = c;\n\n            // D\n            if (i < N - 1 && VW[i][j] == '0') toCell[c][1] = ID(i + 1, j);\n            else toCell[c][1] = c;\n\n            // L\n            if (j > 0 && H[i][j - 1] == '0') toCell[c][2] = ID(i, j - 1);\n            else toCell[c][2] = c;\n\n            // R\n            if (j < N - 1 && H[i][j] == '0') toCell[c][3] = ID(i, j + 1);\n            else toCell[c][3] = c;\n        }\n    }\n\n    // Build undirected adjacency for BFS to target\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            int nc = toCell[c][a];\n            if (nc != c) neighbors[c].push_back(nc);\n        }\n        sort(neighbors[c].begin(), neighbors[c].end());\n        neighbors[c].erase(unique(neighbors[c].begin(), neighbors[c].end()), neighbors[c].end());\n    }\n\n    // Override target transitions: once arrived, process terminates, so treat as absorbing for DP safety\n    for (int a = 0; a < 4; a++) toCell[tid][a] = tid;\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c == tid) {\n                transKind[c][a] = 0;\n            } else if (toCell[c][a] == c) {\n                transKind[c][a] = 0;\n            } else if (toCell[c][a] == tid) {\n                transKind[c][a] = 2;\n            } else {\n                transKind[c][a] = 1;\n            }\n        }\n    }\n}\n\nvoid bfsDistToTarget() {\n    fill(distToT, distToT + V, -1);\n    queue<int> q;\n    distToT[tid] = 0;\n    q.push(tid);\n\n    while (!q.empty()) {\n        int c = q.front();\n        q.pop();\n        for (int nc : neighbors[c]) {\n            if (distToT[nc] == -1) {\n                distToT[nc] = distToT[c] + 1;\n                q.push(nc);\n            }\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c != tid && transKind[c][a] != 0) {\n                int nc = toCell[c][a];\n                spValid[c][a] = (distToT[nc] == distToT[c] - 1);\n            } else {\n                spValid[c][a] = false;\n            }\n        }\n    }\n}\n\nvoid computeAdaptiveUpperBound() {\n    for (int c = 0; c < V; c++) UB[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        UB[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                double val = 0.0;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val = UB[t + 1][c];\n                } else if (k == 2) {\n                    val = hitReward[t] + p_forget * UB[t + 1][c];\n                } else {\n                    int nc = toCell[c][a];\n                    val = p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc];\n                }\n                if (val > best) best = val;\n            }\n            UB[t][c] = best;\n        }\n    }\n}\n\nvector<int> greedyRollout() {\n    vector<int> seq(LMAX, 0);\n    array<double, V> dist{};\n    dist.fill(0.0);\n    dist[sid] = 1.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        int bestA = 0;\n        double bestVal = -1e100;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            double val = 0.0;\n            for (int c = 0; c < V; c++) {\n                double q = dist[c];\n                if (q < 1e-18) continue;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val += q * UB[t + 1][c];\n                } else if (k == 2) {\n                    val += q * (hitReward[t] + p_forget * UB[t + 1][c]);\n                } else {\n                    int nc = toCell[c][a];\n                    val += q * (p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc]);\n                }\n            }\n            if (val > bestVal + 1e-15) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq[t - 1] = bestA;\n\n        array<double, V> nd{};\n        nd.fill(0.0);\n        for (int c = 0; c < V; c++) {\n            double q = dist[c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][bestA];\n            if (k == 0) {\n                nd[c] += q;\n            } else if (k == 2) {\n                nd[c] += q * p_forget;\n            } else {\n                int nc = toCell[c][bestA];\n                nd[c] += q * p_forget;\n                nd[nc] += q * p_move;\n            }\n        }\n        dist = nd;\n    }\n\n    return seq;\n}\n\nstruct CurState {\n    array<double, V> dist;\n    double score;\n};\n\nstruct CandState {\n    array<double, V> dist;\n    double score;\n    double pri;\n    int parent;\n    unsigned char act;\n};\n\nstruct ParentInfo {\n    int parent;\n    unsigned char act;\n};\n\nvector<vector<int>> beamSearch(int beamWidth, int topM) {\n    vector<vector<ParentInfo>> parent(LMAX + 1);\n\n    vector<CurState> cur, nxt;\n    cur.reserve(beamWidth);\n    nxt.reserve(beamWidth);\n\n    CurState start;\n    start.dist.fill(0.0);\n    start.dist[sid] = 1.0;\n    start.score = 0.0;\n    cur.push_back(start);\n\n    vector<CandState> cand;\n    cand.reserve(beamWidth * 4);\n    vector<int> ord;\n\n    for (int t = 1; t <= LMAX; t++) {\n        cand.clear();\n        for (int idx = 0; idx < (int)cur.size(); idx++) {\n            const auto &st = cur[idx];\n            for (int a = 0; a < 4; a++) {\n                CandState cs;\n                cs.dist.fill(0.0);\n                cs.parent = idx;\n                cs.act = (unsigned char)a;\n                double scoreAfter = st.score;\n                double pri = st.score;\n\n                for (int c = 0; c < V; c++) {\n                    double q = st.dist[c];\n                    if (q < 1e-18) continue;\n\n                    unsigned char k = transKind[c][a];\n                    if (k == 0) {\n                        cs.dist[c] += q;\n                        pri += q * UB[t + 1][c];\n                    } else if (k == 2) {\n                        cs.dist[c] += q * p_forget;\n                        scoreAfter += q * hitReward[t];\n                        pri += q * (hitReward[t] + p_forget * UB[t + 1][c]);\n                    } else {\n                        int nc = toCell[c][a];\n                        cs.dist[c] += q * p_forget;\n                        cs.dist[nc] += q * p_move;\n                        pri += q * (p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc]);\n                    }\n                }\n\n                cs.score = scoreAfter;\n                cs.pri = pri;\n                cand.push_back(std::move(cs));\n            }\n        }\n\n        int k = min(beamWidth, (int)cand.size());\n        ord.resize(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n\n        auto cmp = [&](int x, int y) {\n            if (cand[x].pri != cand[y].pri) return cand[x].pri > cand[y].pri;\n            if (cand[x].score != cand[y].score) return cand[x].score > cand[y].score;\n            if (cand[x].parent != cand[y].parent) return cand[x].parent < cand[y].parent;\n            return cand[x].act < cand[y].act;\n        };\n        partial_sort(ord.begin(), ord.begin() + k, ord.end(), cmp);\n\n        nxt.clear();\n        parent[t].resize(k);\n        for (int i = 0; i < k; i++) {\n            int id = ord[i];\n            CurState ns;\n            ns.dist = cand[id].dist;\n            ns.score = cand[id].score;\n            nxt.push_back(std::move(ns));\n            parent[t][i] = ParentInfo{cand[id].parent, cand[id].act};\n        }\n        cur.swap(nxt);\n    }\n\n    vector<int> finalOrd(cur.size());\n    iota(finalOrd.begin(), finalOrd.end(), 0);\n    sort(finalOrd.begin(), finalOrd.end(), [&](int x, int y) {\n        if (cur[x].score != cur[y].score) return cur[x].score > cur[y].score;\n        return x < y;\n    });\n\n    vector<vector<int>> res;\n    topM = min(topM, (int)finalOrd.size());\n    for (int z = 0; z < topM; z++) {\n        int idx = finalOrd[z];\n        vector<int> seq(LMAX);\n        for (int t = LMAX; t >= 1; t--) {\n            seq[t - 1] = parent[t][idx].act;\n            idx = parent[t][idx].parent;\n        }\n        res.push_back(std::move(seq));\n    }\n    return res;\n}\n\nvector<int> buildShortestPathByTurns(bool maximizeTurns) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return distToT[a] < distToT[b];\n    });\n\n    const int INF = 1e9;\n\n    for (int c : ids) {\n        for (int last = 0; last < 5; last++) {\n            if (c == tid) {\n                dpMinTurn[c][last] = 0;\n                dpMaxTurn[c][last] = 0;\n                continue;\n            }\n\n            int bestMin = INF;\n            int bestMax = -INF;\n\n            for (int a = 0; a < 4; a++) {\n                if (!spValid[c][a]) continue;\n                int nc = toCell[c][a];\n                int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n                bestMin = min(bestMin, turnCost + isUL[a] + dpMinTurn[nc][a]);\n                bestMax = max(bestMax, turnCost - isUL[a] + dpMaxTurn[nc][a]);\n            }\n\n            dpMinTurn[c][last] = bestMin;\n            dpMaxTurn[c][last] = bestMax;\n        }\n    }\n\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n\n    while (c != tid) {\n        int bestA = -1;\n        int bestVal = maximizeTurns ? -INF : INF;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n            int val;\n            if (maximizeTurns) {\n                val = turnCost - isUL[a] + dpMaxTurn[nc][a];\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            } else {\n                val = turnCost + isUL[a] + dpMinTurn[nc][a];\n                if (val < bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            }\n        }\n\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n\n    return path;\n}\n\nvector<int> repeatPathTo200(const vector<int> &path) {\n    vector<int> seq(LMAX, 1);\n    if (path.empty()) return seq;\n    for (int t = 0; t < LMAX; t++) seq[t] = path[t % (int)path.size()];\n    return seq;\n}\n\nvoid computeForward(const vector<int> &seq) {\n    fill(preDist[0], preDist[0] + V, 0.0);\n    preDist[0][sid] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        fill(preDist[t], preDist[t] + V, 0.0);\n        int a = seq[t - 1];\n        double sc = prefScore[t - 1];\n\n        for (int c = 0; c < V; c++) {\n            double q = preDist[t - 1][c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                preDist[t][c] += q;\n            } else if (k == 2) {\n                preDist[t][c] += q * p_forget;\n                sc += q * hitReward[t];\n            } else {\n                int nc = toCell[c][a];\n                preDist[t][c] += q * p_forget;\n                preDist[t][nc] += q * p_move;\n            }\n        }\n        prefScore[t] = sc;\n    }\n}\n\nvoid computeBackward(const vector<int> &seq) {\n    for (int c = 0; c < V; c++) sufVal[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        int a = seq[t - 1];\n        sufVal[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                sufVal[t][c] = sufVal[t + 1][c];\n            } else if (k == 2) {\n                sufVal[t][c] = hitReward[t] + p_forget * sufVal[t + 1][c];\n            } else {\n                int nc = toCell[c][a];\n                sufVal[t][c] = p_forget * sufVal[t + 1][c] + p_move * sufVal[t + 1][nc];\n            }\n        }\n    }\n}\n\ndouble localOptimize(vector<int> &seq) {\n    computeForward(seq);\n    double curScore = prefScore[LMAX];\n\n    for (int iter = 0; iter < 200; iter++) {\n        computeBackward(seq);\n\n        double bestScore = curScore + 1e-12;\n        int bestPos = -1;\n        int bestAct = -1;\n\n        for (int t = 1; t <= LMAX; t++) {\n            for (int a = 0; a < 4; a++) {\n                if (a == seq[t - 1]) continue;\n\n                double val = prefScore[t - 1];\n                const double *dist = preDist[t - 1];\n                const double *sv = sufVal[t + 1];\n\n                for (int c = 0; c < V; c++) {\n                    double q = dist[c];\n                    if (q < 1e-18) continue;\n                    unsigned char k = transKind[c][a];\n                    if (k == 0) {\n                        val += q * sv[c];\n                    } else if (k == 2) {\n                        val += q * (hitReward[t] + p_forget * sv[c]);\n                    } else {\n                        int nc = toCell[c][a];\n                        val += q * (p_forget * sv[c] + p_move * sv[nc]);\n                    }\n                }\n\n                if (val > bestScore + 1e-12) {\n                    bestScore = val;\n                    bestPos = t - 1;\n                    bestAct = a;\n                }\n            }\n        }\n\n        if (bestPos == -1) break;\n        seq[bestPos] = bestAct;\n        computeForward(seq);\n        curScore = prefScore[LMAX];\n    }\n\n    return curScore;\n}\n\nstring seqToString(const vector<int> &seq) {\n    string s;\n    s.reserve(seq.size());\n    for (int a : seq) s.push_back(ACT[a]);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj >> ti >> tj >> p_forget;\n    for (int i = 0; i < N; i++) cin >> H[i];\n    for (int i = 0; i < N - 1; i++) cin >> VW[i];\n\n    sid = ID(si, sj);\n    tid = ID(ti, tj);\n    p_move = 1.0 - p_forget;\n\n    for (int t = 1; t <= LMAX; t++) hitReward[t] = p_move * (401 - t);\n\n    buildTransitions();\n    bfsDistToTarget();\n    computeAdaptiveUpperBound();\n\n    vector<vector<int>> candidates;\n\n    // Greedy rollout from adaptive upper bound\n    candidates.push_back(greedyRollout());\n\n    // Beam search candidates\n    auto beamCands = beamSearch(120, 2);\n    for (auto &s : beamCands) candidates.push_back(s);\n\n    // Repeated shortest-path baselines\n    auto minTurnPath = buildShortestPathByTurns(false);\n    auto maxTurnPath = buildShortestPathByTurns(true);\n    candidates.push_back(repeatPathTo200(minTurnPath));\n    candidates.push_back(repeatPathTo200(maxTurnPath));\n\n    // Deduplicate\n    unordered_set<string> seen;\n    vector<vector<int>> uniq;\n    for (auto &seq : candidates) {\n        string key = seqToString(seq);\n        if (seen.insert(key).second) uniq.push_back(seq);\n    }\n\n    double bestScore = -1.0;\n    vector<int> bestSeq = uniq[0];\n\n    for (auto seq : uniq) {\n        double sc = localOptimize(seq);\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestSeq = std::move(seq);\n        }\n    }\n\n    cout << seqToString(bestSeq) << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int P = N * N;\nstatic constexpr int V = P * 4;\n\nstatic constexpr int DIR_L = 0;\nstatic constexpr int DIR_U = 1;\nstatic constexpr int DIR_R = 2;\nstatic constexpr int DIR_D = 3;\n\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int MATCH_REWARD = 2;\nstatic constexpr int BROKEN_PENALTY = -3;\nstatic constexpr int BOUNDARY_PENALTY = -3;\n\nstatic constexpr long long SCORE_FACTOR = 10000000000LL;\nstatic constexpr long long L2_FACTOR = 1000000LL;\nstatic constexpr long long L1_FACTOR = 100LL;\n\nusing StateArray = array<uint8_t, P>;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 1) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstruct Eval {\n    long long score = -1;\n    long long scalar = LLONG_MIN / 4;\n    int L1 = 0;\n    int L2 = 0;\n    int total = 0;\n    int g = 0;\n    int numCycles = 0;\n};\n\nstruct Candidate {\n    StateArray st{};\n    Eval ev;\n};\n\nstatic const int TO[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\nstatic chrono::steady_clock::time_point g_start;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nuint8_t activeMask[8];\nuint8_t stateToRot[8][8];\nuint8_t allowedState[P][4];\nuint8_t allowedCnt[P];\nuint8_t baseTile[P];\nbool isDoublePos[P];\nint16_t neighborPos[P][4];\nvector<int> allPos;\nvector<int> doublePos;\n\ninline int rotate_state(int b, int r) {\n    if (b <= 3) return (b + r) & 3;\n    if (b <= 5) return 4 + ((b - 4 + r) & 1);\n    return 6 + ((b - 6 + r) & 1);\n}\n\nvoid init_tables() {\n    for (int s = 0; s < 8; s++) {\n        uint8_t mask = 0;\n        for (int d = 0; d < 4; d++) {\n            if (TO[s][d] != -1) mask |= uint8_t(1u << d);\n        }\n        activeMask[s] = mask;\n    }\n\n    for (int b = 0; b < 8; b++) {\n        for (int s = 0; s < 8; s++) stateToRot[b][s] = 255;\n        for (int r = 0; r < 4; r++) {\n            int s = rotate_state(b, r);\n            stateToRot[b][s] = min<int>(stateToRot[b][s], r);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            neighborPos[p][DIR_L] = (j > 0 ? p - 1 : -1);\n            neighborPos[p][DIR_U] = (i > 0 ? p - N : -1);\n            neighborPos[p][DIR_R] = (j + 1 < N ? p + 1 : -1);\n            neighborPos[p][DIR_D] = (i + 1 < N ? p + N : -1);\n        }\n    }\n}\n\ninline int localCellScore(int pos, uint8_t s, const StateArray& st) {\n    int sc = 0;\n    uint8_t mask = activeMask[s];\n    for (int d = 0; d < 4; d++) {\n        bool a = (mask >> d) & 1u;\n        int np = neighborPos[pos][d];\n        if (np == -1) {\n            if (a) sc += BOUNDARY_PENALTY;\n        } else {\n            bool b = (activeMask[st[np]] >> opp[d]) & 1u;\n            if (a && b) sc += MATCH_REWARD;\n            else if (a != b) sc += BROKEN_PENALTY;\n        }\n    }\n    return sc;\n}\n\nvoid shuffle_vec(vector<int>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.next_int(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nvoid optimizeLocalG(StateArray& st, RNG& rng, int sweeps = 8) {\n    vector<int> order = allPos;\n    for (int sw = 0; sw < sweeps; sw++) {\n        shuffle_vec(order, rng);\n        bool changed = false;\n\n        for (int pos : order) {\n            if (isDoublePos[pos]) continue;\n\n            uint8_t cur = st[pos];\n            int curScore = localCellScore(pos, cur, st);\n            int bestScore = curScore;\n            uint8_t bests[4];\n            int bc = 0;\n\n            for (int k = 0; k < allowedCnt[pos]; k++) {\n                uint8_t ns = allowedState[pos][k];\n                if (ns == cur) continue;\n                int sc = localCellScore(pos, ns, st);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bests[0] = ns;\n                    bc = 1;\n                } else if (sc == bestScore && sc > curScore) {\n                    bests[bc++] = ns;\n                }\n            }\n\n            if (bestScore > curScore) {\n                uint8_t chosen = bests[rng.next_int(bc)];\n                st[pos] = chosen;\n                changed = true;\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nEval evaluate(const StateArray& st) {\n    Eval res;\n\n    // Global local score G\n    int g = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            uint8_t m = activeMask[st[p]];\n\n            if (j == 0 && (m & (1u << DIR_L))) g += BOUNDARY_PENALTY;\n            if (i == 0 && (m & (1u << DIR_U))) g += BOUNDARY_PENALTY;\n\n            if (j + 1 < N) {\n                bool a = (m >> DIR_R) & 1u;\n                bool b = (activeMask[st[p + 1]] >> DIR_L) & 1u;\n                if (a && b) g += MATCH_REWARD;\n                else if (a != b) g += BROKEN_PENALTY;\n            } else {\n                if (m & (1u << DIR_R)) g += BOUNDARY_PENALTY;\n            }\n\n            if (i + 1 < N) {\n                bool a = (m >> DIR_D) & 1u;\n                bool b = (activeMask[st[p + N]] >> DIR_U) & 1u;\n                if (a && b) g += MATCH_REWARD;\n                else if (a != b) g += BROKEN_PENALTY;\n            } else {\n                if (m & (1u << DIR_D)) g += BOUNDARY_PENALTY;\n            }\n        }\n    }\n    res.g = g;\n\n    // Exact loop detection on active-port graph\n    static uint8_t vis[V];\n    static int stk[V];\n    memset(vis, 0, sizeof(vis));\n\n    int L1 = 0, L2 = 0, total = 0, numCycles = 0;\n\n    for (int p = 0; p < P; p++) {\n        uint8_t s = st[p];\n        uint8_t mask = activeMask[s];\n        int base = p << 2;\n\n        while (mask) {\n            int d = __builtin_ctz(mask);\n            mask &= mask - 1;\n            int v = base + d;\n            if (vis[v]) continue;\n\n            bool isCycle = true;\n            int vertices = 0;\n            int top = 0;\n            stk[top++] = v;\n            vis[v] = 1;\n\n            while (top) {\n                int u = stk[--top];\n                vertices++;\n\n                int pp = u >> 2;\n                int dd = u & 3;\n                uint8_t ss = st[pp];\n\n                // internal mate\n                int md = TO[ss][dd];\n                int u2 = (pp << 2) + md;\n                if (!vis[u2]) {\n                    vis[u2] = 1;\n                    stk[top++] = u2;\n                }\n\n                // external connection\n                int np = neighborPos[pp][dd];\n                if (np != -1 && ((activeMask[st[np]] >> opp[dd]) & 1u)) {\n                    int u3 = (np << 2) + opp[dd];\n                    if (!vis[u3]) {\n                        vis[u3] = 1;\n                        stk[top++] = u3;\n                    }\n                } else {\n                    isCycle = false;\n                }\n            }\n\n            if (isCycle) {\n                int len = vertices / 2;\n                total += len;\n                numCycles++;\n                if (len > L1) {\n                    L2 = L1;\n                    L1 = len;\n                } else if (len > L2) {\n                    L2 = len;\n                }\n            }\n        }\n    }\n\n    res.L1 = L1;\n    res.L2 = L2;\n    res.total = total;\n    res.numCycles = numCycles;\n    res.score = (numCycles >= 2 ? 1LL * L1 * L2 : 0LL);\n    res.scalar = res.score * SCORE_FACTOR\n               + 1LL * L2 * L2_FACTOR\n               + 1LL * L1 * L1_FACTOR\n               + 2LL * total\n               + g;\n    return res;\n}\n\nvoid addPool(vector<Candidate>& pool, const StateArray& st, int keep = 6) {\n    Candidate c;\n    c.st = st;\n    c.ev = evaluate(st);\n    pool.push_back(c);\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n    if ((int)pool.size() > keep) pool.resize(keep);\n}\n\nvoid applyDoublePattern(StateArray& st, int patId) {\n    for (int p : doublePos) {\n        int i = p / N, j = p % N;\n        uint8_t v = 4;\n        switch (patId) {\n            case 0: v = 4; break;\n            case 1: v = 5; break;\n            case 2: v = ((i + j) & 1) ? 4 : 5; break;\n            case 3: v = ((i + j) & 1) ? 5 : 4; break;\n            case 4: v = (i & 1) ? 4 : 5; break;\n            case 5: v = (i & 1) ? 5 : 4; break;\n            case 6: v = (j & 1) ? 4 : 5; break;\n            case 7: v = (j & 1) ? 5 : 4; break;\n            default: v = 4; break;\n        }\n        st[p] = v;\n    }\n}\n\nvoid applyDoubleRandomMode(StateArray& st, RNG& rng, int mode) {\n    if (mode == 0) {\n        for (int p : doublePos) st[p] = uint8_t(4 + rng.next_int(2));\n    } else if (mode == 1) {\n        uint8_t rowv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = rowv[p / N];\n    } else {\n        uint8_t colv[N];\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = colv[p % N];\n    }\n}\n\nvoid hillClimb(StateArray& st, Eval& curEv, const vector<int>& positions, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = positions;\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t bestState = orig;\n            Eval bestEv = curEv;\n\n            for (int k = 0; k < allowedCnt[pos]; k++) {\n                uint8_t ns = allowedState[pos][k];\n                if (ns == orig) continue;\n                st[pos] = ns;\n                Eval ev = evaluate(st);\n                if (ev.scalar > bestEv.scalar) {\n                    bestEv = ev;\n                    bestState = ns;\n                }\n            }\n\n            st[pos] = bestState;\n            if (bestState != orig) {\n                curEv = bestEv;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid perturb(StateArray& st, RNG& rng, int stagnation) {\n    bool changed = false;\n\n    if (doublePos.empty() || rng.next_int(100) < 60) {\n        int k = 4 + rng.next_int(5) + min(12, stagnation / 3);\n        for (int t = 0; t < k; t++) {\n            int pos;\n            if (!doublePos.empty() && rng.next_int(100) < 70) {\n                pos = doublePos[rng.next_int((int)doublePos.size())];\n            } else {\n                pos = rng.next_int(P);\n            }\n\n            if (allowedCnt[pos] <= 1) continue;\n            uint8_t cur = st[pos];\n            uint8_t ns = cur;\n            for (int trial = 0; trial < 8 && ns == cur; trial++) {\n                ns = allowedState[pos][rng.next_int(allowedCnt[pos])];\n            }\n            if (ns != cur) {\n                st[pos] = ns;\n                changed = true;\n            }\n        }\n    } else {\n        int h = 2 + rng.next_int(min(10, N) - 1);\n        int w = 2 + rng.next_int(min(10, N) - 1);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) {\n                    st[p] = (st[p] == 4 ? 5 : 4);\n                    changed = true;\n                } else if (rng.next_int(100) < 10 && allowedCnt[p] > 1) {\n                    uint8_t cur = st[p];\n                    uint8_t ns = cur;\n                    for (int trial = 0; trial < 8 && ns == cur; trial++) {\n                        ns = allowedState[p][rng.next_int(allowedCnt[p])];\n                    }\n                    if (ns != cur) {\n                        st[p] = ns;\n                        changed = true;\n                    }\n                }\n            }\n        }\n    }\n\n    if (!changed) {\n        int pos = rng.next_int(P);\n        if (allowedCnt[pos] > 1) {\n            uint8_t cur = st[pos];\n            for (int trial = 0; trial < 8; trial++) {\n                uint8_t ns = allowedState[pos][rng.next_int(allowedCnt[pos])];\n                if (ns != cur) {\n                    st[pos] = ns;\n                    break;\n                }\n            }\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n    init_tables();\n\n    uint64_t seed = 1469598103934665603ULL;\n    vector<string> S(N);\n    for (int i = 0; i < N; i++) {\n        cin >> S[i];\n        for (char c : S[i]) {\n            seed ^= uint64_t((unsigned char)c + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    RNG rng(seed);\n\n    allPos.reserve(P);\n    doublePos.reserve(P);\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            int b = S[i][j] - '0';\n            baseTile[p] = (uint8_t)b;\n            isDoublePos[p] = (b == 4 || b == 5);\n            allPos.push_back(p);\n            if (isDoublePos[p]) doublePos.push_back(p);\n\n            int cnt = 0;\n            for (int s = 0; s < 8; s++) {\n                if (stateToRot[b][s] != 255) {\n                    allowedState[p][cnt++] = (uint8_t)s;\n                }\n            }\n            allowedCnt[p] = (uint8_t)cnt;\n        }\n    }\n\n    const double deadline = 1.92;\n\n    vector<Candidate> pool;\n    int baseConfigs = 6;\n\n    for (int it = 0; it < baseConfigs; it++) {\n        if (elapsed_sec() > 0.25) break;\n\n        StateArray baseSt{};\n        for (int p = 0; p < P; p++) {\n            if (isDoublePos[p]) {\n                baseSt[p] = 4;\n            } else {\n                baseSt[p] = allowedState[p][rng.next_int(allowedCnt[p])];\n            }\n        }\n\n        optimizeLocalG(baseSt, rng, 8);\n\n        for (int pat = 0; pat < 8; pat++) {\n            StateArray cand = baseSt;\n            applyDoublePattern(cand, pat);\n            addPool(pool, cand, 6);\n        }\n        for (int mode = 0; mode < 3; mode++) {\n            StateArray cand = baseSt;\n            applyDoubleRandomMode(cand, rng, mode);\n            addPool(pool, cand, 6);\n        }\n    }\n\n    if (pool.empty()) {\n        StateArray st{};\n        for (int p = 0; p < P; p++) st[p] = allowedState[p][0];\n        if (!doublePos.empty()) applyDoubleRandomMode(st, rng, 0);\n        optimizeLocalG(st, rng, 8);\n        addPool(pool, st, 6);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    int refineCount = min<int>(pool.size(), 4);\n    for (int i = 0; i < refineCount; i++) {\n        if (elapsed_sec() > 0.80) break;\n        hillClimb(pool[i].st, pool[i].ev, doublePos, rng, 2, deadline);\n        hillClimb(pool[i].st, pool[i].ev, allPos, rng, 2, deadline);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    Candidate best = pool[0];\n    Candidate current = best;\n    int stagnation = 0;\n\n    while (elapsed_sec() < deadline - 0.08) {\n        StateArray trial = (rng.next_int(100) < 55 ? current.st : best.st);\n        perturb(trial, rng, stagnation);\n        Eval tev = evaluate(trial);\n\n        hillClimb(trial, tev, doublePos, rng, 1, deadline);\n        hillClimb(trial, tev, allPos, rng, 1, deadline);\n\n        if (tev.scalar > best.ev.scalar) {\n            best.st = trial;\n            best.ev = tev;\n            stagnation = 0;\n        } else {\n            stagnation++;\n        }\n\n        if (tev.scalar > current.ev.scalar || rng.next_int(100) < 20) {\n            current.st = trial;\n            current.ev = tev;\n        }\n    }\n\n    hillClimb(best.st, best.ev, doublePos, rng, 2, deadline);\n    hillClimb(best.st, best.ev, allPos, rng, 10, deadline);\n\n    string ans;\n    ans.resize(P);\n    for (int p = 0; p < P; p++) {\n        uint8_t r = stateToRot[baseTile[p]][best.st[p]];\n        if (r == 255) r = 0;\n        ans[p] = char('0' + r);\n    }\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nstatic constexpr int MAXC = 100;\n\nstruct Metrics {\n    int tree;\n    int largest_comp;\n    int matched;\n    int potential;\n    int sum_potential;\n    long long beam_score;\n};\n\nstruct Node {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1; // 0:U 1:D 2:L 3:R\n    int tree = 1;\n    long long beam_score = 0;\n};\n\nstruct Cand {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1;\n    short parent = -1;\n    char mv = '?';\n    int tree = 1;\n    long long beam_score = 0;\n};\n\nstruct Solver {\n    int N, T, NN, FULL;\n    array<int, MAXC> nxtU, nxtD, nxtL, nxtR, nxtPos[4];\n    array<array<ull, 16>, MAXC> zob{};\n    chrono::steady_clock::time_point st;\n    double time_limit_sec = 2.75;\n\n    static ull splitmix64(ull &x) {\n        ull z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    bool time_over() const {\n        double elapsed = chrono::duration<double>(chrono::steady_clock::now() - st).count();\n        return elapsed >= time_limit_sec;\n    }\n\n    static int hexval(char c) {\n        if ('0' <= c && c <= '9') return c - '0';\n        return c - 'a' + 10;\n    }\n\n    string build_path(int depth, int idx,\n                      const vector<vector<short>> &parents,\n                      const vector<string> &moves) {\n        string res(depth, '?');\n        while (depth > 0) {\n            res[depth - 1] = moves[depth][idx];\n            idx = parents[depth][idx];\n            --depth;\n        }\n        return res;\n    }\n\n    Metrics evaluate(const array<unsigned char, MAXC> &b) const {\n        static int parent[MAXC];\n        static int sz[MAXC];\n        static int ed[MAXC];\n\n        for (int i = 0; i < NN; i++) {\n            if (b[i] == 0) {\n                parent[i] = -1;\n                sz[i] = 0;\n                ed[i] = 0;\n            } else {\n                parent[i] = i;\n                sz[i] = 1;\n                ed[i] = 0;\n            }\n        }\n\n        auto find = [&](int x) {\n            while (parent[x] != x) {\n                parent[x] = parent[parent[x]];\n                x = parent[x];\n            }\n            return x;\n        };\n\n        auto unite_edge = [&](int a, int c) {\n            int ra = find(a), rb = find(c);\n            if (ra == rb) {\n                ed[ra]++;\n            } else {\n                if (sz[ra] < sz[rb]) swap(ra, rb);\n                parent[rb] = ra;\n                sz[ra] += sz[rb];\n                ed[ra] += ed[rb] + 1;\n            }\n        };\n\n        int matched = 0;\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n\n            int r = nxtR[i];\n            if (r != -1) {\n                unsigned char tr = b[r];\n                if ((t & 4) && (tr & 1)) {\n                    unite_edge(i, r);\n                    matched++;\n                }\n            }\n\n            int d = nxtD[i];\n            if (d != -1) {\n                unsigned char td = b[d];\n                if ((t & 8) && (td & 2)) {\n                    unite_edge(i, d);\n                    matched++;\n                }\n            }\n        }\n\n        int largest_tree = 1;\n        int largest_comp = 1;\n        int best_pot = 1;\n        int sum_pot = 0;\n        constexpr int ALPHA = 3;\n\n        for (int i = 0; i < NN; i++) {\n            if (parent[i] == i) {\n                int v = sz[i];\n                int ex = ed[i] - v + 1;\n                if (ex < 0) ex = 0;\n                int pot = max(0, v - ALPHA * ex);\n\n                largest_comp = max(largest_comp, v);\n                if (ed[i] == v - 1) largest_tree = max(largest_tree, v);\n                best_pot = max(best_pot, pot);\n                sum_pot += pot;\n            }\n        }\n\n        long long beam =\n            1'000'000'000'000LL * best_pot +\n            1'000'000'000LL * largest_tree +\n            1'000'000LL * largest_comp +\n            1'000LL * matched +\n            sum_pot;\n\n        return {largest_tree, largest_comp, matched, best_pot, sum_pot, beam};\n    }\n\n    string beam_search(const array<unsigned char, MAXC> &start_board, int start_blank) {\n        Node root;\n        root.b = start_board;\n        root.blank = start_blank;\n        root.last = -1;\n        root.h = 0;\n        for (int i = 0; i < NN; i++) root.h ^= zob[i][root.b[i]];\n        {\n            auto m = evaluate(root.b);\n            root.tree = m.tree;\n            root.beam_score = m.beam_score;\n        }\n\n        string best_ans = \"\";\n        int best_tree = root.tree;\n        if (best_tree == FULL) return best_ans;\n\n        int WIDTH = max(120, 1'400'000 / max(1, 3 * T));\n        WIDTH = min(WIDTH, 600);\n\n        vector<Node> cur, next;\n        cur.reserve(WIDTH);\n        next.reserve(WIDTH);\n        cur.push_back(root);\n\n        vector<vector<short>> parents(T + 1);\n        vector<string> moves(T + 1);\n        parents[0].push_back(-1);\n        moves[0].push_back('?');\n\n        unordered_set<ull> seen;\n        seen.reserve((size_t)WIDTH * (size_t)T * 2 + 1024);\n        seen.max_load_factor(0.7f);\n        seen.insert(root.h);\n\n        const int inv[4] = {1, 0, 3, 2};\n        const char dirc[4] = {'U', 'D', 'L', 'R'};\n\n        for (int depth = 0; depth < T; depth++) {\n            if (time_over()) break;\n\n            vector<Cand> cands;\n            cands.reserve(cur.size() * 3 + 4);\n\n            for (int pi = 0; pi < (int)cur.size(); pi++) {\n                const Node &nd = cur[pi];\n                if ((pi & 31) == 0 && time_over()) break;\n\n                for (int dir = 0; dir < 4; dir++) {\n                    if (nd.last != -1 && inv[dir] == nd.last) continue;\n                    int nb = nxtPos[dir][nd.blank];\n                    if (nb == -1) continue;\n\n                    unsigned char tile = nd.b[nb];\n                    ull nh = nd.h ^ zob[nd.blank][0] ^ zob[nb][tile] ^ zob[nd.blank][tile] ^ zob[nb][0];\n                    if (seen.find(nh) != seen.end()) continue;\n\n                    Cand cd;\n                    cd.b = nd.b;\n                    cd.b[nd.blank] = tile;\n                    cd.b[nb] = 0;\n                    cd.h = nh;\n                    cd.blank = nb;\n                    cd.last = (signed char)dir;\n                    cd.parent = (short)pi;\n                    cd.mv = dirc[dir];\n\n                    auto m = evaluate(cd.b);\n                    cd.tree = m.tree;\n                    cd.beam_score = m.beam_score;\n                    cands.push_back(std::move(cd));\n\n                    if (m.tree > best_tree) {\n                        best_tree = m.tree;\n                        best_ans = build_path(depth, pi, parents, moves);\n                        best_ans.push_back(dirc[dir]);\n                        if (best_tree == FULL) return best_ans;\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [](const Cand &a, const Cand &b) {\n                if (a.beam_score != b.beam_score) return a.beam_score > b.beam_score;\n                return a.h < b.h;\n            });\n\n            unordered_set<ull> used;\n            used.reserve(cands.size() * 2 + 1);\n            used.max_load_factor(0.7f);\n\n            next.clear();\n            parents[depth + 1].clear();\n            moves[depth + 1].clear();\n            parents[depth + 1].reserve(min(WIDTH, (int)cands.size()));\n            moves[depth + 1].reserve(min(WIDTH, (int)cands.size()));\n\n            for (auto &cd : cands) {\n                if (used.find(cd.h) != used.end()) continue;\n                used.insert(cd.h);\n                if (seen.find(cd.h) != seen.end()) continue;\n\n                Node nd;\n                nd.b = cd.b;\n                nd.h = cd.h;\n                nd.blank = cd.blank;\n                nd.last = cd.last;\n                nd.tree = cd.tree;\n                nd.beam_score = cd.beam_score;\n\n                next.push_back(std::move(nd));\n                parents[depth + 1].push_back(cd.parent);\n                moves[depth + 1].push_back(cd.mv);\n                seen.insert(cd.h);\n\n                if ((int)next.size() >= WIDTH) break;\n            }\n\n            if (next.empty()) break;\n            cur.swap(next);\n        }\n\n        return best_ans;\n    }\n\n    void solve() {\n        cin >> N >> T;\n        NN = N * N;\n        FULL = NN - 1;\n\n        array<unsigned char, MAXC> board{};\n        int blank = -1;\n        for (int i = 0; i < N; i++) {\n            string s;\n            cin >> s;\n            for (int j = 0; j < N; j++) {\n                int v = hexval(s[j]);\n                board[i * N + j] = (unsigned char)v;\n                if (v == 0) blank = i * N + j;\n            }\n        }\n\n        for (int i = 0; i < NN; i++) {\n            int r = i / N, c = i % N;\n            nxtU[i] = (r > 0 ? i - N : -1);\n            nxtD[i] = (r + 1 < N ? i + N : -1);\n            nxtL[i] = (c > 0 ? i - 1 : -1);\n            nxtR[i] = (c + 1 < N ? i + 1 : -1);\n            nxtPos[0][i] = nxtU[i];\n            nxtPos[1][i] = nxtD[i];\n            nxtPos[2][i] = nxtL[i];\n            nxtPos[3][i] = nxtR[i];\n        }\n\n        ull seed = 1234567891234567ULL;\n        for (int i = 0; i < NN; i++) {\n            for (int v = 0; v < 16; v++) {\n                zob[i][v] = splitmix64(seed);\n            }\n        }\n\n        st = chrono::steady_clock::now();\n        string ans = beam_search(board, blank);\n        cout << ans << '\\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}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\nstatic constexpr int R = 10000;\nstatic constexpr int MAX_CUTS = 100;\nstatic constexpr int NORMAL_MAX = 4096;\nstatic constexpr int MIN_NORM = 1000;\nstatic constexpr long double SQRT3 = 1.7320508075688772935L;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Line {\n    int A, B; // primitive-ish normal, sign-normalized\n    ll C;     // A x + B y = C\n};\n\nstruct State {\n    vector<int> cell;      // cell id of each point\n    vector<int> cellSize;  // size of each cell\n    array<int, 11> hist{}; // hist[d] = number of cells with d strawberries\n    int rawScore = 0;\n};\n\nstruct Cand2 {\n    int A, B;\n    int t1, t2;\n    double alpha1, alpha2;\n    double off1, off2;\n};\n\nstruct Cand3 {\n    array<pair<int,int>,3> n;\n    int t[3];\n    double alpha[3];\n    double off[3];\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double uniform() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    double uniform(double l, double r) {\n        return l + (r - l) * uniform();\n    }\n    ll next_ll(ll l, ll r) {\n        if (l > r) swap(l, r);\n        unsigned long long w = (unsigned long long)(r - l + 1);\n        return l + (ll)(next() % w);\n    }\n    int next_int(int l, int r) {\n        return (int)next_ll(l, r);\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 ed = chrono::steady_clock::now();\n        return chrono::duration<double>(ed - st).count();\n    }\n};\n\nint N, K;\nint a_need[11];\nint attendees_sum = 0;\nvector<Pt> pts;\nXorShift64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\ntemplate <class T>\nT clampv(T x, T l, T r) {\n    return min(r, max(l, x));\n}\n\nstatic inline ll proj(int A, int B, const Pt& p) {\n    return 1LL * A * p.x + 1LL * B * p.y;\n}\n\nstatic inline ll norm2(pair<int,int> p) {\n    return 1LL * p.first * p.first + 1LL * p.second * p.second;\n}\n\npair<int,int> normalize_pair(ll A, ll B) {\n    if (A == 0 && B == 0) return {0, 0};\n    ll g = std::gcd(std::llabs(A), std::llabs(B));\n    A /= g;\n    B /= g;\n    if (A < 0 || (A == 0 && B < 0)) {\n        A = -A;\n        B = -B;\n    }\n    return {(int)A, (int)B};\n}\n\nLine normalize_line(Line ln) {\n    if (ln.A < 0 || (ln.A == 0 && ln.B < 0)) {\n        ln.A = -ln.A;\n        ln.B = -ln.B;\n        ln.C = -ln.C;\n    }\n    return ln;\n}\n\npair<int,int> random_primitive_large() {\n    while (true) {\n        ll A = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        ll B = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        if (A == 0 && B == 0) continue;\n        auto p = normalize_pair(A, B);\n        if (norm2(p) < 1LL * MIN_NORM * MIN_NORM) continue;\n        return p;\n    }\n}\n\npair<int,int> rotate60(pair<int,int> p) {\n    long double x = 0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first + 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\npair<int,int> rotate120(pair<int,int> p) {\n    long double x = -0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first - 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\nvoid recompute_score(State& st) {\n    st.hist.fill(0);\n    for (int s : st.cellSize) {\n        if (1 <= s && s <= 10) st.hist[s]++;\n    }\n    st.rawScore = 0;\n    for (int d = 1; d <= 10; d++) st.rawScore += min(a_need[d], st.hist[d]);\n}\n\nint index_from_proj(ll u, ll start, ll step, int t) {\n    ll d = u - start;\n    if (d < 0) return 0;\n    ll q = d / step;\n    if (q >= t) return t;\n    if (d % step == 0) return -1; // on line\n    return (int)q + 1;\n}\n\nint raw_from_counts(const vector<int>& cnt) {\n    array<int, 11> hist{};\n    for (int c : cnt) {\n        if (1 <= c && c <= 10) hist[c]++;\n    }\n    int raw = 0;\n    for (int d = 1; d <= 10; d++) raw += min(a_need[d], hist[d]);\n    return raw;\n}\n\nint eval_cand2(const Cand2& c) {\n    static vector<int> cnt;\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    int A1 = c.A, B1 = c.B;\n    int A2 = -c.B, B2 = c.A;\n\n    int W = c.t2 + 1;\n    int SZ = (c.t1 + 1) * (c.t2 + 1);\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int i = index_from_proj(proj(A1, B1, p), start1, step1, c.t1);\n        if (i < 0) continue;\n        int j = index_from_proj(proj(A2, B2, p), start2, step2, c.t2);\n        if (j < 0) continue;\n        cnt[i * W + j]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nint eval_cand3(const Cand3& c) {\n    static vector<int> cnt;\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    int W1 = c.t[1] + 1;\n    int W2 = c.t[2] + 1;\n    int SZ = (c.t[0] + 1) * W1 * W2;\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int idx[3];\n        bool bad = false;\n        for (int k = 0; k < 3; k++) {\n            idx[k] = index_from_proj(proj(c.n[k].first, c.n[k].second, p), start[k], step[k], c.t[k]);\n            if (idx[k] < 0) {\n                bad = true;\n                break;\n            }\n        }\n        if (bad) continue;\n        int id = (idx[0] * W1 + idx[1]) * W2 + idx[2];\n        cnt[id]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nbool point_on_line(const Line& ln, const Pt& p) {\n    return proj(ln.A, ln.B, p) == ln.C;\n}\n\nvoid avoid_collisions(Line& ln) {\n    ll base = ln.C;\n    auto coll = [&](ll C) -> bool {\n        for (const auto& p : pts) {\n            if (proj(ln.A, ln.B, p) == C) return true;\n        }\n        return false;\n    };\n    if (!coll(base)) return;\n    for (ll d = 1;; d++) {\n        if (!coll(base + d)) {\n            ln.C = base + d;\n            return;\n        }\n        if (!coll(base - d)) {\n            ln.C = base - d;\n            return;\n        }\n    }\n}\n\nvector<Line> build_lines2(const Cand2& c, vector<pair<int,int>>& normals_out) {\n    normals_out.clear();\n    auto n1 = normalize_pair(c.A, c.B);\n    auto n2 = normalize_pair(-c.B, c.A);\n    normals_out.push_back(n1);\n    normals_out.push_back(n2);\n\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    vector<Line> res;\n    res.reserve(c.t1 + c.t2);\n\n    for (int j = 0; j < c.t1; j++) {\n        Line ln{c.A, c.B, start1 + 1LL * j * step1};\n        ln = normalize_line(ln);\n        avoid_collisions(ln);\n        res.push_back(ln);\n    }\n    for (int j = 0; j < c.t2; j++) {\n        Line ln{-c.B, c.A, start2 + 1LL * j * step2};\n        ln = normalize_line(ln);\n        avoid_collisions(ln);\n        res.push_back(ln);\n    }\n    return res;\n}\n\nvector<Line> build_lines3(const Cand3& c, vector<pair<int,int>>& normals_out) {\n    normals_out.clear();\n    for (int k = 0; k < 3; k++) normals_out.push_back(normalize_pair(c.n[k].first, c.n[k].second));\n\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    vector<Line> res;\n    res.reserve(c.t[0] + c.t[1] + c.t[2]);\n\n    for (int k = 0; k < 3; k++) {\n        for (int j = 0; j < c.t[k]; j++) {\n            Line ln{c.n[k].first, c.n[k].second, start[k] + 1LL * j * step[k]};\n            ln = normalize_line(ln);\n            avoid_collisions(ln);\n            res.push_back(ln);\n        }\n    }\n    return res;\n}\n\nvoid apply_line(State& st, const Line& ln) {\n    int M = (int)st.cellSize.size();\n    static vector<int> pos, neg, newPosId, newNegId;\n    static vector<unsigned char> side;\n    pos.assign(M, 0);\n    neg.assign(M, 0);\n    side.assign(N, 0);\n\n    for (int i = 0; i < N; i++) {\n        ll v = proj(ln.A, ln.B, pts[i]) - ln.C;\n        int id = st.cell[i];\n        if (v > 0) {\n            side[i] = 1;\n            pos[id]++;\n        } else {\n            side[i] = 0;\n            neg[id]++;\n        }\n    }\n\n    newPosId.assign(M, -1);\n    newNegId.assign(M, -1);\n    vector<int> newSizes;\n    newSizes.reserve(min(N, 2 * M));\n\n    for (int id = 0; id < M; id++) {\n        if (neg[id] > 0) {\n            newNegId[id] = (int)newSizes.size();\n            newSizes.push_back(neg[id]);\n        }\n        if (pos[id] > 0) {\n            newPosId[id] = (int)newSizes.size();\n            newSizes.push_back(pos[id]);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        int old = st.cell[i];\n        st.cell[i] = side[i] ? newPosId[old] : newNegId[old];\n    }\n    st.cellSize.swap(newSizes);\n    recompute_score(st);\n}\n\nState build_state(const vector<Line>& lines) {\n    State st;\n    st.cell.assign(N, 0);\n    st.cellSize = {N};\n    recompute_score(st);\n    for (const auto& ln : lines) apply_line(st, ln);\n    return st;\n}\n\nint eval_add_line(const State& st, const Line& ln) {\n    int M = (int)st.cellSize.size();\n    static vector<int> pos, neg;\n    pos.assign(M, 0);\n    neg.assign(M, 0);\n\n    for (int i = 0; i < N; i++) {\n        ll v = proj(ln.A, ln.B, pts[i]) - ln.C;\n        if (v == 0) return -1000000000;\n        int id = st.cell[i];\n        if (v > 0) pos[id]++;\n        else neg[id]++;\n    }\n\n    array<int, 11> hist = st.hist;\n    for (int id = 0; id < M; id++) {\n        int old = st.cellSize[id];\n        if (1 <= old && old <= 10) hist[old]--;\n        if (1 <= pos[id] && pos[id] <= 10) hist[pos[id]]++;\n        if (1 <= neg[id] && neg[id] <= 10) hist[neg[id]]++;\n    }\n\n    int raw = 0;\n    for (int d = 1; d <= 10; d++) raw += min(a_need[d], hist[d]);\n    return raw;\n}\n\nbool better(int raw, int numLines, int bestRaw, int bestLines) {\n    return (raw > bestRaw) || (raw == bestRaw && numLines < bestLines);\n}\n\nCand2 random_cand2() {\n    Cand2 c;\n    auto n = random_primitive_large();\n    c.A = n.first;\n    c.B = n.second;\n\n    double avg = (double)N / attendees_sum;\n    double lambda = clampv(avg * exp(rng.uniform(-0.9, 0.9)), 1.2, 12.0);\n    double Ctarget = N / lambda;\n    double aspect = exp(rng.uniform(-0.8, 0.8));\n    double prod = 4.0 * Ctarget / acos(-1.0);\n\n    c.t1 = max(1, (int)llround(sqrt(prod * aspect) - 1.0));\n    c.t2 = max(1, (int)llround(sqrt(prod / aspect) - 1.0));\n\n    int sum = c.t1 + c.t2;\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        c.t1 = max(1, (int)floor(c.t1 * sc));\n        c.t2 = max(1, (int)floor(c.t2 * sc));\n        while (c.t1 + c.t2 > MAX_CUTS) {\n            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n            else if (c.t2 > 1) c.t2--;\n            else break;\n        }\n    }\n\n    c.alpha1 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.alpha2 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.off1 = rng.uniform(-0.5, 0.5);\n    c.off2 = rng.uniform(-0.5, 0.5);\n    return c;\n}\n\nCand3 random_cand3() {\n    Cand3 c;\n    while (true) {\n        auto n0 = random_primitive_large();\n        auto n1 = rotate60(n0);\n        auto n2 = rotate120(n0);\n        if ((n1.first || n1.second) && (n2.first || n2.second)\n            && norm2(n1) >= 250000 && norm2(n2) >= 250000) {\n            c.n[0] = n0;\n            c.n[1] = n1;\n            c.n[2] = n2;\n            break;\n        }\n    }\n\n    double avg = (double)N / attendees_sum;\n    double lambda = clampv(avg * exp(rng.uniform(-0.8, 0.8)), 1.2, 12.0);\n    double Ctarget = N / lambda;\n    double base = sqrt(max(1.0, Ctarget / 3.0));\n\n    for (int k = 0; k < 3; k++) {\n        c.t[k] = max(1, (int)llround(base * exp(rng.uniform(-0.45, 0.45))));\n    }\n\n    int sum = c.t[0] + c.t[1] + c.t[2];\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        for (int k = 0; k < 3; k++) c.t[k] = max(1, (int)floor(c.t[k] * sc));\n        while (c.t[0] + c.t[1] + c.t[2] > MAX_CUTS) {\n            int id = 0;\n            if (c.t[1] > c.t[id]) id = 1;\n            if (c.t[2] > c.t[id]) id = 2;\n            if (c.t[id] > 1) c.t[id]--;\n            else break;\n        }\n    }\n\n    for (int k = 0; k < 3; k++) {\n        c.alpha[k] = clampv(exp(rng.uniform(-0.35, 0.35)), 0.55, 1.6);\n        c.off[k] = rng.uniform(-0.5, 0.5);\n    }\n    return c;\n}\n\nvector<pair<int,int>> unique_normals(const vector<Line>& lines) {\n    set<pair<int,int>> s;\n    for (auto& ln : lines) s.insert(normalize_pair(ln.A, ln.B));\n    return vector<pair<int,int>>(s.begin(), s.end());\n}\n\npair<int,int> combine_normals(pair<int,int> a, pair<int,int> b, int sign) {\n    ll A = (ll)a.first + sign * (ll)b.first;\n    ll B = (ll)a.second + sign * (ll)b.second;\n    auto p = normalize_pair(A, B);\n    if (p.first == 0 && p.second == 0) return random_primitive_large();\n    if (norm2(p) < 40000) return random_primitive_large();\n    return p;\n}\n\nLine random_aug_line(const vector<pair<int,int>>& pref, int curLines) {\n    pair<int,int> n;\n    double r = rng.uniform();\n    if (!pref.empty() && r < 0.55) {\n        n = pref[rng.next_int(0, (int)pref.size() - 1)];\n    } else if ((int)pref.size() >= 2 && r < 0.78) {\n        int i = rng.next_int(0, (int)pref.size() - 1);\n        int j = rng.next_int(0, (int)pref.size() - 1);\n        while (j == i) j = rng.next_int(0, (int)pref.size() - 1);\n        n = combine_normals(pref[i], pref[j], (rng.next() & 1) ? 1 : -1);\n    } else {\n        n = random_primitive_large();\n    }\n\n    long double g = sqrt((long double)n.first * n.first + (long double)n.second * n.second);\n    ll lim = llround(1.05L * R * g);\n\n    ll C;\n    if (rng.uniform() < 0.75) {\n        int idx = rng.next_int(0, N - 1);\n        ll p = proj(n.first, n.second, pts[idx]);\n        ll span = max<ll>(1, lim / max(20, 10 + curLines));\n        ll delta = rng.next_ll(1, span);\n        if (rng.next() & 1) delta = -delta;\n        C = clampv(p + delta, -lim, lim);\n    } else {\n        C = rng.next_ll(-lim, lim);\n    }\n\n    Line ln{n.first, n.second, C};\n    ln = normalize_line(ln);\n    return ln;\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = (a >= 0 ? 1 : -1);\n        y = 0;\n        return std::llabs(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\nll modinv(ll a, ll mod) {\n    if (mod == 1) return 0;\n    ll x, y;\n    ll g = extgcd(a, mod, x, y);\n    if (g != 1) return 0;\n    x %= mod;\n    if (x < 0) x += mod;\n    return x;\n}\n\narray<ll,4> line_to_points(const Line& ln) {\n    const ll LIM = 1000000000LL - 5;\n    ll A = ln.A, B = ln.B, C = ln.C;\n\n    if (B == 0) {\n        ll x = C / A;\n        return {x, -LIM, x, LIM};\n    }\n    if (A == 0) {\n        ll y = C / B;\n        return {-LIM, y, LIM, y};\n    }\n\n    ll b = std::llabs(B);\n    ll a = ((A % b) + b) % b;\n    ll c = ((C % b) + b) % b;\n    ll inv = modinv(a, b);\n    ll x0 = (ll)((__int128)inv * c % b);\n    ll y0 = (C - A * x0) / B;\n\n    ll t1 = (LIM - std::llabs(x0)) / std::llabs(B);\n    ll t2 = (LIM - std::llabs(y0)) / std::llabs(A);\n    ll t = min(t1, t2);\n    t = min<ll>(t, 200000);\n    if (t < 1) t = 1;\n\n    ll x1 = x0 - B * t;\n    ll y1 = y0 + A * t;\n    ll x2 = x0 + B * t;\n    ll y2 = y0 - A * t;\n\n    while ((std::llabs(x1) > LIM || std::llabs(y1) > LIM ||\n            std::llabs(x2) > LIM || std::llabs(y2) > LIM) && t > 1) {\n        t /= 2;\n        x1 = x0 - B * t;\n        y1 = y0 + A * t;\n        x2 = x0 + B * t;\n        y2 = y0 - A * t;\n    }\n    return {x1, y1, x2, y2};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    for (int d = 1; d <= 10; d++) {\n        cin >> a_need[d];\n        attendees_sum += a_need[d];\n    }\n    pts.resize(N);\n    for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n    Timer timer;\n    const double SEARCH_END = 2.10;\n    const double TOTAL_END  = 2.85;\n\n    vector<Line> bestLines;\n    vector<pair<int,int>> bestPrefNormals;\n    int bestRaw = 0;\n\n    // Baseline: 0 cuts\n    {\n        State st = build_state({});\n        bestRaw = st.rawScore;\n        bestLines.clear();\n        bestPrefNormals.clear();\n    }\n\n    // A few deterministic-ish seeds\n    for (double alpha : {0.8, 1.0, 1.25}) {\n        Cand2 c;\n        auto n = random_primitive_large();\n        c.A = n.first;\n        c.B = n.second;\n        double Ctarget = attendees_sum;\n        double prod = 4.0 * Ctarget / acos(-1.0);\n        c.t1 = c.t2 = max(1, (int)llround(sqrt(prod) - 1.0));\n        while (c.t1 + c.t2 > MAX_CUTS) {\n            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n            else if (c.t2 > 1) c.t2--;\n            else break;\n        }\n        c.alpha1 = c.alpha2 = alpha;\n        c.off1 = c.off2 = 0.0;\n\n        vector<pair<int,int>> norms;\n        auto lines = build_lines2(c, norms);\n        State st = build_state(lines);\n        if (better(st.rawScore, (int)lines.size(), bestRaw, (int)bestLines.size())) {\n            bestRaw = st.rawScore;\n            bestLines = lines;\n            bestPrefNormals = norms;\n        }\n    }\n\n    // Random search over 2-bundle / 3-bundle tessellations\n    while (timer.elapsed() < SEARCH_END) {\n        bool use3 = (rng.next() % 10 < 3); // 30% 3-bundle\n        if (!use3) {\n            Cand2 c = random_cand2();\n            int approx = eval_cand2(c);\n            int cuts = c.t1 + c.t2;\n            if (better(approx, cuts, bestRaw, (int)bestLines.size())) {\n                vector<pair<int,int>> norms;\n                auto lines = build_lines2(c, norms);\n                State st = build_state(lines);\n                if (better(st.rawScore, (int)lines.size(), bestRaw, (int)bestLines.size())) {\n                    bestRaw = st.rawScore;\n                    bestLines = lines;\n                    bestPrefNormals = norms;\n                }\n            }\n        } else {\n            Cand3 c = random_cand3();\n            int approx = eval_cand3(c);\n            int cuts = c.t[0] + c.t[1] + c.t[2];\n            if (better(approx, cuts, bestRaw, (int)bestLines.size())) {\n                vector<pair<int,int>> norms;\n                auto lines = build_lines3(c, norms);\n                State st = build_state(lines);\n                if (better(st.rawScore, (int)lines.size(), bestRaw, (int)bestLines.size())) {\n                    bestRaw = st.rawScore;\n                    bestLines = lines;\n                    bestPrefNormals = norms;\n                }\n            }\n        }\n    }\n\n    // Exact greedy augmentation\n    State cur = build_state(bestLines);\n    vector<Line> curLines = bestLines;\n    vector<pair<int,int>> pref = bestPrefNormals;\n    if (pref.empty()) pref = unique_normals(curLines);\n\n    int noImprove = 0;\n    while ((int)curLines.size() < K && timer.elapsed() < TOTAL_END && noImprove < 6 && cur.rawScore < attendees_sum) {\n        int localBest = cur.rawScore;\n        Line bestLn{1, 0, (ll)4e18};\n        int trials = (timer.elapsed() < 2.55 ? 128 : 64);\n\n        for (int it = 0; it < trials; it++) {\n            Line ln = random_aug_line(pref, (int)curLines.size());\n            int sc = eval_add_line(cur, ln);\n            if (sc > localBest) {\n                localBest = sc;\n                bestLn = ln;\n            }\n        }\n\n        if (localBest > cur.rawScore) {\n            avoid_collisions(bestLn);\n            int sc2 = eval_add_line(cur, bestLn);\n            if (sc2 > cur.rawScore) {\n                apply_line(cur, bestLn);\n                curLines.push_back(bestLn);\n                auto n = normalize_pair(bestLn.A, bestLn.B);\n                bool exists = false;\n                for (auto& p : pref) if (p == n) exists = true;\n                if (!exists && (int)pref.size() < 8) pref.push_back(n);\n                noImprove = 0;\n            } else {\n                noImprove++;\n            }\n        } else {\n            noImprove++;\n        }\n    }\n\n    cout << curLines.size() << '\\n';\n    for (const auto& ln : curLines) {\n        auto pt = line_to_points(ln);\n        cout << pt[0] << ' ' << pt[1] << ' ' << pt[2] << ' ' << pt[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int MAXID = MAXN * MAXN;\nstatic constexpr int MAXD = 2 * MAXN - 1;\n\nint GX[MAXID], GY[MAXID];\n\ninline int enc(int x, int y) { return y * MAXN + x; }\n\nstruct CoordInit {\n    CoordInit() {\n        for (int y = 0; y < MAXN; ++y) {\n            for (int x = 0; x < MAXN; ++x) {\n                int id = enc(x, y);\n                GX[id] = x;\n                GY[id] = y;\n            }\n        }\n    }\n} coord_init;\n\nstruct Operation {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n};\n\nstruct Candidate {\n    Operation op;\n    double key;\n    int gain;\n    int cost;\n};\n\nstruct Params {\n    double lambda;\n    int topK;\n    int randDepth;\n};\n\nclass Solver {\n    enum Dir {\n        LEFT = 0, RIGHT = 1, DOWN = 2, UP = 3,\n        NE = 4, NW = 5, SW = 6, SE = 7\n    };\n\n    static constexpr int KEEP = 32;\n    static constexpr double EPS = 1e-12;\n\n    int N, M, c;\n    vector<int> initialIds;\n    vector<int> cellOrder;\n    array<pair<int,int>, 8> pairs{\n        pair<int,int>{LEFT, DOWN},\n        pair<int,int>{LEFT, UP},\n        pair<int,int>{RIGHT, DOWN},\n        pair<int,int>{RIGHT, UP},\n        pair<int,int>{NE, NW},\n        pair<int,int>{NE, SE},\n        pair<int,int>{SW, NW},\n        pair<int,int>{SW, SE}\n    };\n\n    int weight[MAXN][MAXN]{};\n\n    // current state\n    unsigned char dot[MAXN][MAXN]{};\n    unsigned char useH[MAXN - 1][MAXN]{};\n    unsigned char useV[MAXN][MAXN - 1]{};\n    unsigned char useD1[MAXN - 1][MAXN - 1]{};\n    unsigned char useD2[MAXN - 1][MAXN - 1]{};\n\n    int nearDot[8][MAXN][MAXN]{};\n\n    int prefH[MAXN][MAXN + 1]{};\n    int prefV[MAXN][MAXN + 1]{};\n    int prefD1[MAXD][MAXN + 1]{};\n    int prefD2[MAXD][MAXN + 1]{};\n\n    long long initialWeight = 0;\n    long long curWeight = 0;\n    long long bestWeight = 0;\n\n    vector<Operation> ops;\n    vector<Operation> bestOps;\n\n    mt19937_64 rng;\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    static bool betterCand(const Candidate& a, const Candidate& b) {\n        if (a.key > b.key + EPS) return true;\n        if (a.key + EPS < b.key) return false;\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return false;\n    }\n\n    void consider(vector<Candidate>& top, const Candidate& cand) {\n        int pos = (int)top.size();\n        while (pos > 0 && betterCand(cand, top[pos - 1])) --pos;\n        if (pos >= KEEP) return;\n        top.insert(top.begin() + pos, cand);\n        if ((int)top.size() > KEEP) top.pop_back();\n    }\n\n    int chooseIndex(int lim) {\n        if (lim <= 1) return 0;\n        uint64_t sum = (uint64_t)lim * (lim + 1) / 2;\n        uint64_t r = rng() % sum;\n        uint64_t acc = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (uint64_t)(lim - i);\n            if (r < acc) return i;\n        }\n        return 0;\n    }\n\n    void resetState() {\n        memset(dot, 0, sizeof(dot));\n        memset(useH, 0, sizeof(useH));\n        memset(useV, 0, sizeof(useV));\n        memset(useD1, 0, sizeof(useD1));\n        memset(useD2, 0, sizeof(useD2));\n        for (int id : initialIds) {\n            dot[GX[id]][GY[id]] = 1;\n        }\n        curWeight = initialWeight;\n        ops.clear();\n    }\n\n    void recomputeAux() {\n        // nearest on rows\n        for (int y = 0; y < N; ++y) {\n            int last = -1;\n            for (int x = 0; x < N; ++x) {\n                nearDot[LEFT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int x = N - 1; x >= 0; --x) {\n                nearDot[RIGHT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // nearest on columns\n        for (int x = 0; x < N; ++x) {\n            int last = -1;\n            for (int y = 0; y < N; ++y) {\n                nearDot[DOWN][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int y = N - 1; y >= 0; --y) {\n                nearDot[UP][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // nearest on main diagonals (x - y = const)\n        for (int d = -(N - 1); d <= (N - 1); ++d) {\n            int minx = max(0, d);\n            int maxx = min(N - 1, N - 1 + d);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = x - d;\n                nearDot[SW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = x - d;\n                nearDot[NE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // nearest on anti-diagonals (x + y = const)\n        for (int s = 0; s <= 2 * (N - 1); ++s) {\n            int minx = max(0, s - (N - 1));\n            int maxx = min(N - 1, s);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = s - x;\n                nearDot[NW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = s - x;\n                nearDot[SE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // prefix sums of used segments\n        for (int y = 0; y < N; ++y) {\n            prefH[y][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int add = (x < N - 1 ? useH[x][y] : 0);\n                prefH[y][x + 1] = prefH[y][x] + add;\n            }\n        }\n\n        for (int x = 0; x < N; ++x) {\n            prefV[x][0] = 0;\n            for (int y = 0; y < N; ++y) {\n                int add = (y < N - 1 ? useV[x][y] : 0);\n                prefV[x][y + 1] = prefV[x][y] + add;\n            }\n        }\n\n        for (int didx = 0; didx < 2 * N - 1; ++didx) {\n            int d = didx - (N - 1);\n            prefD1[didx][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = x - d;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD1[x][y];\n                prefD1[didx][x + 1] = prefD1[didx][x] + add;\n            }\n        }\n\n        for (int s = 0; s < 2 * N - 1; ++s) {\n            prefD2[s][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = s - x - 1;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD2[x][y];\n                prefD2[s][x + 1] = prefD2[s][x] + add;\n            }\n        }\n    }\n\n    int usedCountOnSegment(int x1, int y1, int x2, int y2) const {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefH[y1][r] - prefH[y1][l];\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            return prefV[x1][r] - prefV[x1][l];\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + (N - 1);\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD1[d][r] - prefD1[d][l];\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD2[s][r] - prefD2[s][l];\n        }\n    }\n\n    void markSegment(int x1, int y1, int x2, int y2) {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) useH[x][y1] = 1;\n            return;\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            for (int y = l; y < r; ++y) useV[x1][y] = 1;\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = x - d;\n                useD1[x][y] = 1;\n            }\n            return;\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = s - x - 1;\n                useD2[x][y] = 1;\n            }\n            return;\n        }\n    }\n\n    void apply(const Candidate& cand) {\n        const auto& o = cand.op;\n        dot[o.x1][o.y1] = 1;\n        curWeight += weight[o.x1][o.y1];\n\n        markSegment(o.x1, o.y1, o.x2, o.y2);\n        markSegment(o.x2, o.y2, o.x3, o.y3);\n        markSegment(o.x3, o.y3, o.x4, o.y4);\n        markSegment(o.x4, o.y4, o.x1, o.y1);\n\n        ops.push_back(o);\n    }\n\n    void runAttempt(const Params& prm, chrono::steady_clock::time_point deadline) {\n        resetState();\n        int step = 0;\n\n        while (true) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            recomputeAux();\n\n            vector<Candidate> top;\n            top.reserve(KEEP);\n\n            for (int id1 : cellOrder) {\n                int x = GX[id1], y = GY[id1];\n                if (dot[x][y]) continue;\n\n                int gain = weight[x][y];\n\n                if ((int)top.size() == KEEP) {\n                    double upperBound = gain - prm.lambda * 2.0; // min cost = 1 + 1\n                    if (upperBound + EPS < top.back().key) break;\n                }\n\n                for (auto [da, db] : pairs) {\n                    int id2 = nearDot[da][x][y];\n                    if (id2 < 0) continue;\n                    int id4 = nearDot[db][x][y];\n                    if (id4 < 0) continue;\n\n                    int x2 = GX[id2], y2 = GY[id2];\n                    int x4 = GX[id4], y4 = GY[id4];\n\n                    int x3 = x2 + x4 - x;\n                    int y3 = y2 + y4 - y;\n                    if (!inside(x3, y3)) continue;\n                    if (!dot[x3][y3]) continue;\n\n                    int id3 = enc(x3, y3);\n\n                    // rule 2 (no other dots on perimeter) via nearest-dot relations\n                    if (nearDot[db][x2][y2] != id3) continue;\n                    if (nearDot[da][x4][y4] != id3) continue;\n\n                    // rule 3 (no reused positive-length segment)\n                    if (usedCountOnSegment(x, y, x2, y2)) continue;\n                    if (usedCountOnSegment(x2, y2, x3, y3)) continue;\n                    if (usedCountOnSegment(x3, y3, x4, y4)) continue;\n                    if (usedCountOnSegment(x4, y4, x, y)) continue;\n\n                    int len1 = max(abs(x2 - x), abs(y2 - y));\n                    int len2 = max(abs(x4 - x), abs(y4 - y));\n                    int cost = len1 + len2;\n\n                    Candidate cand{\n                        Operation{x, y, x2, y2, x3, y3, x4, y4},\n                        gain - prm.lambda * cost,\n                        gain,\n                        cost\n                    };\n                    consider(top, cand);\n                }\n            }\n\n            if (top.empty()) break;\n\n            int idx = 0;\n            if (step < prm.randDepth && prm.topK > 1) {\n                idx = chooseIndex(min(prm.topK, (int)top.size()));\n            }\n            apply(top[idx]);\n            ++step;\n        }\n\n        if (curWeight > bestWeight) {\n            bestWeight = curWeight;\n            bestOps = ops;\n        }\n    }\n\npublic:\n    Solver(int N_, int M_, const vector<pair<int,int>>& pts) : N(N_), M(M_), c((N_ - 1) / 2) {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)N * 1000003ULL;\n        seed ^= (uint64_t)M * 10007ULL;\n        rng.seed(seed);\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                weight[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n                cellOrder.push_back(enc(x, y));\n            }\n        }\n\n        stable_sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n            int xa = GX[a], ya = GY[a];\n            int xb = GX[b], yb = GY[b];\n            if (weight[xa][ya] != weight[xb][yb]) return weight[xa][ya] > weight[xb][yb];\n            int ma = abs(xa - c) + abs(ya - c);\n            int mb = abs(xb - c) + abs(yb - c);\n            if (ma != mb) return ma > mb;\n            return a < b;\n        });\n\n        for (auto [x, y] : pts) {\n            int id = enc(x, y);\n            initialIds.push_back(id);\n            initialWeight += weight[x][y];\n        }\n\n        curWeight = bestWeight = initialWeight;\n        ops.reserve(N * N);\n        bestOps.reserve(N * N);\n    }\n\n    void solve() {\n        auto start = chrono::steady_clock::now();\n        auto deadline = start + chrono::milliseconds(4700);\n\n        vector<Params> fixed = {\n            {12.0, 1, 0},\n            {8.0,  1, 0},\n            {4.0,  1, 0},\n            {2.0,  1, 0},\n            {1.0,  1, 0},\n            {0.5,  1, 0},\n            {0.25, 1, 0},\n            {0.0,  1, 0},\n            {4.0,  4, 10},\n            {2.0,  6, 16},\n            {1.0,  8, 24},\n            {0.5, 10, 32},\n        };\n\n        for (const auto& prm : fixed) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            runAttempt(prm, deadline);\n        }\n\n        static const vector<double> lambdas = {\n            0.0, 0.1, 0.2, 0.35, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 12.0\n        };\n        static const vector<int> ks = {2, 3, 4, 5, 6, 8, 10, 12};\n        static const vector<int> depths = {4, 8, 12, 16, 24, 32, 48, 64};\n\n        while (chrono::steady_clock::now() < deadline) {\n            Params prm;\n            prm.lambda = lambdas[(size_t)(rng() % lambdas.size())];\n            prm.topK = ks[(size_t)(rng() % ks.size())];\n            prm.randDepth = depths[(size_t)(rng() % depths.size())];\n\n            // sometimes run a fully deterministic greedy with a random lambda\n            if ((rng() & 7ULL) == 0) {\n                prm.topK = 1;\n                prm.randDepth = 0;\n            }\n\n            runAttempt(prm, deadline);\n        }\n    }\n\n    void output() const {\n        cout << bestOps.size() << '\\n';\n        for (const auto& o : bestOps) {\n            cout << o.x1 << ' ' << o.y1 << ' '\n                 << o.x2 << ' ' << o.y2 << ' '\n                 << o.x3 << ' ' << o.y3 << ' '\n                 << o.x4 << ' ' << o.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<pair<int,int>> pts(M);\n    for (int i = 0; i < M; ++i) {\n        cin >> pts[i].first >> pts[i].second;\n    }\n\n    Solver solver(N, M, pts);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Board {\n    array<uint8_t, 100> a;\n};\n\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'}; // F: up, B: down, L: left, R: right\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstruct Analysis {\n    int compSq = 0;\n    int largest[4] = {};\n    int compCnt[4] = {};\n    int sameAdj = 0;\n    int diffAdj = 0;\n    int dispersion = 0;\n};\n\nclass Solver {\n    static constexpr double TIME_LIMIT = 1.90;\n\n    int flavor[101]{};\n    int suffixCnt[103][4]{}; // suffixCnt[t][c] = count of flavor c in [t..100]\n    Board cur{};\n    SplitMix64 rng;\n    chrono::steady_clock::time_point st;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    static inline void place_by_rank(Board &b, int rank, int f) {\n        for (int i = 0; i < 100; ++i) {\n            if (b.a[i] == 0) {\n                if (--rank == 0) {\n                    b.a[i] = (uint8_t)f;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline void apply_tilt(const Board &src, int dir, Board &dst) {\n        dst.a.fill(0);\n        if (dir == 0) { // F = up\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 0;\n                for (int r = 0; r < 10; ++r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[ptr++ * 10 + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B = down\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 9;\n                for (int r = 9; r >= 0; --r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[ptr-- * 10 + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L = left\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 0;\n                for (int c = 0; c < 10; ++c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + ptr++] = v;\n                }\n            }\n        } else { // R = right\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 9;\n                for (int c = 9; c >= 0; --c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + ptr--] = v;\n                }\n            }\n        }\n    }\n\n    static int comp_sq_only(const Board &b) {\n        uint8_t vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    static Analysis analyze(const Board &b) {\n        Analysis e;\n        int cnt[4] = {};\n        int sr[4] = {}, sc[4] = {}, sr2[4] = {}, sc2[4] = {};\n\n        for (int r = 0; r < 10; ++r) {\n            for (int c = 0; c < 10; ++c) {\n                int id = r * 10 + c;\n                uint8_t col = b.a[id];\n                if (!col) continue;\n\n                cnt[col]++;\n                sr[col] += r;\n                sc[col] += c;\n                sr2[col] += r * r;\n                sc2[col] += c * c;\n\n                if (c + 1 < 10 && b.a[id + 1]) {\n                    if (b.a[id + 1] == col) e.sameAdj++;\n                    else e.diffAdj++;\n                }\n                if (r + 1 < 10 && b.a[id + 10]) {\n                    if (b.a[id + 10] == col) e.sameAdj++;\n                    else e.diffAdj++;\n                }\n            }\n        }\n\n        uint8_t vis[100] = {};\n        int q[100];\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n\n            e.compSq += sz * sz;\n            e.largest[col] = max(e.largest[col], sz);\n            e.compCnt[col]++;\n        }\n\n        for (int c = 1; c <= 3; ++c) {\n            if (cnt[c] == 0) continue;\n            e.dispersion += cnt[c] * sr2[c] - sr[c] * sr[c];\n            e.dispersion += cnt[c] * sc2[c] - sc[c] * sc[c];\n        }\n\n        return e;\n    }\n\n    long long heuristic(const Board &b, int step) const {\n        Analysis e = analyze(b);\n\n        long long optimistic = e.compSq;\n        long long compPenalty = 0;\n        for (int c = 1; c <= 3; ++c) {\n            int rem = suffixCnt[step + 1][c];\n            optimistic += 2LL * e.largest[c] * rem;\n            compPenalty += 1LL * max(0, e.compCnt[c] - 1) * rem;\n        }\n\n        return optimistic * 1000LL\n             - compPenalty * 200LL\n             + 40LL * e.sameAdj\n             - 25LL * e.diffAdj\n             - 3LL * e.dispersion;\n    }\n\n    double exact_expect(const Board &state_after_tilt, int step) {\n        int next = step + 1;\n        int holes = 101 - next; // number of empty cells before placing candy 'next'\n        double sum = 0.0;\n\n        for (int rank = 1; rank <= holes; ++rank) {\n            Board b = state_after_tilt;\n            place_by_rank(b, rank, flavor[next]);\n\n            if (next == 100) {\n                sum += comp_sq_only(b);\n            } else {\n                double best = -1e100;\n                Board tmp;\n                for (int d = 0; d < 4; ++d) {\n                    apply_tilt(b, d, tmp);\n                    best = max(best, exact_expect(tmp, next));\n                }\n                sum += best;\n            }\n        }\n        return sum / holes;\n    }\n\n    int greedy_best_dir(const Board &after_insert, int step, Board &best_board_out) const {\n        long long bestH = LLONG_MIN;\n        int bestD = 0;\n        Board tmp;\n        for (int d = 0; d < 4; ++d) {\n            apply_tilt(after_insert, d, tmp);\n            long long h = heuristic(tmp, step);\n            if (h > bestH) {\n                bestH = h;\n                bestD = d;\n                best_board_out = tmp;\n            }\n        }\n        return bestD;\n    }\n\n    int choose_dir(const Board &after_insert, int step) {\n        if (step == 100) return 0;\n\n        int rem = 100 - step;\n\n        Board first[4];\n        long long baseH[4];\n        for (int d = 0; d < 4; ++d) {\n            apply_tilt(after_insert, d, first[d]);\n            baseH[d] = heuristic(first[d], step);\n        }\n\n        int greedyBest = 0;\n        for (int d = 1; d < 4; ++d) {\n            if (baseH[d] > baseH[greedyBest]) greedyBest = d;\n        }\n\n        if (elapsed() > TIME_LIMIT - 0.03) return greedyBest;\n\n        // Exact search in the endgame.\n        if (rem <= 5 && elapsed() < TIME_LIMIT - 0.03) {\n            double bestVal = -1e100;\n            int bestD = greedyBest;\n            for (int d = 0; d < 4; ++d) {\n                double v = exact_expect(first[d], step);\n                if (v > bestVal + 1e-12 || (fabs(v - bestVal) <= 1e-12 && baseH[d] > baseH[bestD])) {\n                    bestVal = v;\n                    bestD = d;\n                }\n            }\n            return bestD;\n        }\n\n        // Monte Carlo with common random numbers.\n        int K = min(20, max(4, 400 / rem));\n        long long sumFinal[4] = {};\n        int done = 0;\n\n        int ranks[101];\n        for (int k = 0; k < K; ++k) {\n            if (elapsed() > TIME_LIMIT - 0.03) break;\n\n            for (int u = step + 1; u <= 100; ++u) {\n                ranks[u] = 1 + rng.next_int(101 - u);\n            }\n\n            for (int d = 0; d < 4; ++d) {\n                Board sim = first[d];\n                for (int u = step + 1; u <= 100; ++u) {\n                    place_by_rank(sim, ranks[u], flavor[u]);\n                    if (u == 100) break;\n\n                    Board nextBestBoard;\n                    greedy_best_dir(sim, u, nextBestBoard);\n                    sim = nextBestBoard;\n                }\n                sumFinal[d] += comp_sq_only(sim);\n            }\n            ++done;\n        }\n\n        if (done == 0) return greedyBest;\n\n        double bestScore = -1e100;\n        int bestD = greedyBest;\n        for (int d = 0; d < 4; ++d) {\n            double avgFinal = (double)sumFinal[d] / done;\n            double score = avgFinal * 3000.0 + (double)baseH[d];\n            if (score > bestScore) {\n                bestScore = score;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 1; i <= 100; ++i) cin >> flavor[i];\n\n        for (int c = 1; c <= 3; ++c) suffixCnt[101][c] = 0;\n        for (int t = 100; t >= 1; --t) {\n            for (int c = 1; c <= 3; ++c) suffixCnt[t][c] = suffixCnt[t + 1][c];\n            suffixCnt[t][flavor[t]]++;\n        }\n\n        uint64_t seed = 0x123456789abcdefULL;\n        for (int i = 1; i <= 100; ++i) {\n            seed = seed * 6364136223846793005ULL + (uint64_t)(flavor[i] + 1);\n        }\n        rng = SplitMix64(seed);\n\n        cur.a.fill(0);\n        st = chrono::steady_clock::now();\n\n        for (int t = 1; t <= 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place_by_rank(cur, p, flavor[t]);\n\n            int d = choose_dir(cur, t);\n\n            Board nxt;\n            apply_tilt(cur, d, nxt);\n            cur = nxt;\n\n            cout << DIR_CH[d] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Candidate {\n    vector<int> parts;   // partition of B, nondecreasing\n    vector<int> deg;     // base sorted degree vector, length B\n    int edgeCnt = 0;     // base edge count\n};\n\nstatic long long dist2_deg(const vector<int>& a, const vector<int>& b) {\n    long long s = 0;\n    for (int i = 0; i < (int)a.size(); i++) {\n        long long d = (long long)a[i] - b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstatic vector<Candidate> generate_partitions(int B) {\n    vector<Candidate> res;\n    vector<int> cur;\n\n    function<void(int,int)> dfs = [&](int rem, int last) {\n        if (rem == 0) {\n            Candidate c;\n            c.parts = cur;\n            c.deg.reserve(B);\n            int edges = 0;\n            for (int s : cur) {\n                edges += s * (s - 1) / 2;\n                for (int t = 0; t < s; t++) c.deg.push_back(s - 1);\n            }\n            c.edgeCnt = edges;\n            res.push_back(std::move(c));\n            return;\n        }\n        for (int x = last; x <= rem; x++) {\n            cur.push_back(x);\n            dfs(rem - x, x);\n            cur.pop_back();\n        }\n    };\n    dfs(B, 1);\n    return res;\n}\n\nstatic double selection_quality(const vector<Candidate>& cands, const vector<int>& sel) {\n    int m = (int)sel.size();\n    if (m <= 1) return 0.0;\n    long long sum_nn = 0;\n    for (int i = 0; i < m; i++) {\n        long long best = (1LL << 60);\n        for (int j = 0; j < m; j++) if (i != j) {\n            best = min(best, dist2_deg(cands[sel[i]].deg, cands[sel[j]].deg));\n        }\n        sum_nn += best;\n    }\n    return (double)sum_nn / m;\n}\n\nstatic vector<Candidate> select_codewords(const vector<Candidate>& cands, int M) {\n    int C = (int)cands.size();\n    if (C <= M) {\n        vector<Candidate> ret = cands;\n        sort(ret.begin(), ret.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.edgeCnt != b.edgeCnt) return a.edgeCnt < b.edgeCnt;\n            return a.parts < b.parts;\n        });\n        return ret;\n    }\n\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int i, int j) {\n        if (cands[i].edgeCnt != cands[j].edgeCnt) return cands[i].edgeCnt < cands[j].edgeCnt;\n        return cands[i].parts < cands[j].parts;\n    });\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQual = -1.0;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<long long> minDist(C, (1LL << 60));\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                long long d = dist2_deg(cands[x].deg, cands[i].deg);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        };\n\n        add_one(seed);\n        if (M >= 2) {\n            int far = -1;\n            long long best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                long long d = dist2_deg(cands[seed].deg, cands[i].deg);\n                if (d > best) {\n                    best = d;\n                    far = i;\n                }\n            }\n            add_one(far);\n        }\n\n        while ((int)sel.size() < M) {\n            int nxt = -1;\n            long long best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double qual = selection_quality(cands, sel);\n        if (qual > bestQual) {\n            bestQual = qual;\n            bestSel = sel;\n        }\n    }\n\n    vector<Candidate> ret;\n    ret.reserve(M);\n    for (int id : bestSel) ret.push_back(cands[id]);\n    sort(ret.begin(), ret.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.edgeCnt != b.edgeCnt) return a.edgeCnt < b.edgeCnt;\n        return a.parts < b.parts;\n    });\n    return ret;\n}\n\nstatic vector<double> build_expected_degree_vector(const vector<int>& parts, int q, double eps) {\n    int B = 0;\n    for (int x : parts) B += x;\n    int N = B * q;\n    double shift = eps * (N - 1);\n    double scale = 1.0 - 2.0 * eps;\n\n    vector<double> mu;\n    mu.reserve(N);\n    for (int x : parts) {\n        int s = x * q;\n        double v = shift + scale * (s - 1);\n        for (int i = 0; i < s; i++) mu.push_back(v);\n    }\n    return mu;\n}\n\nstatic string build_graph_string(const vector<int>& parts, int q) {\n    int B = 0;\n    for (int x : parts) B += x;\n    int N = B * q;\n\n    vector<int> block(N);\n    int ptr = 0, bid = 0;\n    for (int x : parts) {\n        int s = x * q;\n        for (int i = 0; i < s; i++) block[ptr++] = bid;\n        ++bid;\n    }\n\n    string g;\n    g.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            g.push_back(block[i] == block[j] ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic vector<int> q_candidates(int qmax) {\n    vector<int> qs;\n    if (qmax <= 12) {\n        for (int q = 1; q <= qmax; q++) qs.push_back(q);\n    } else {\n        for (int q = 1; q <= 8; q++) qs.push_back(q);\n        for (int q : {10, 12, 14, 16, 18, 20}) if (q <= qmax) qs.push_back(q);\n        qs.push_back(qmax);\n        sort(qs.begin(), qs.end());\n        qs.erase(unique(qs.begin(), qs.end()), qs.end());\n    }\n    return qs;\n}\n\nstatic double estimate_proxy_score(\n    const vector<Candidate>& codes, int B, int q, int M, double eps, int reps\n) {\n    int N = B * q;\n    double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n\n    vector<vector<double>> exps(M);\n    for (int i = 0; i < M; i++) {\n        exps[i] = build_expected_degree_vector(codes[i].parts, q, eps);\n    }\n\n    mt19937_64 rng(0x123456789ULL + 10007ULL * B + 1000003ULL * q);\n    normal_distribution<double> gauss(0.0, sigma);\n\n    int err = 0;\n    int tot = M * reps;\n    vector<double> noisy(N);\n\n    for (int rep = 0; rep < reps; rep++) {\n        for (int i = 0; i < M; i++) {\n            const auto& mu = exps[i];\n            for (int j = 0; j < N; j++) {\n                double x = mu[j];\n                if (sigma > 0) x += gauss(rng);\n                x = std::clamp(x, 0.0, (double)(N - 1));\n                x = std::round(x);\n                noisy[j] = x;\n            }\n            sort(noisy.begin(), noisy.end());\n\n            int bestId = -1;\n            double bestS = 1e100;\n            for (int t = 0; t < M; t++) {\n                const auto& v = exps[t];\n                double s = 0.0;\n                for (int j = 0; j < N; j++) {\n                    double d = noisy[j] - v[j];\n                    s += d * d;\n                    if (s >= bestS) break;\n                }\n                if (s < bestS) {\n                    bestS = s;\n                    bestId = t;\n                }\n            }\n            if (bestId != i) err++;\n        }\n    }\n\n    double errRate = (double)err / tot;\n    return pow(0.9, 100.0 * errRate) / N;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    // partition numbers p(n) up to 25\n    const int BMAX = 23;\n    vector<long long> p(BMAX + 1, 0);\n    p[0] = 1;\n    for (int x = 1; x <= BMAX; x++) {\n        for (int s = x; s <= BMAX; s++) p[s] += p[s - x];\n    }\n\n    int Bmin = 1;\n    while (Bmin <= BMAX && p[Bmin] < M) Bmin++;\n    if (Bmin > BMAX) Bmin = BMAX;\n\n    int Bhi = min(BMAX, Bmin + 10);\n\n    struct BaseBook {\n        int B;\n        vector<Candidate> codes;\n    };\n    vector<BaseBook> books;\n\n    for (int B = Bmin; B <= Bhi; B++) {\n        auto cands = generate_partitions(B);\n        if ((int)cands.size() < M) continue;\n        auto codes = select_codewords(cands, M);\n        books.push_back({B, std::move(codes)});\n    }\n\n    int bestB = -1, bestQ = -1, bestN = -1;\n    double bestScore = -1.0;\n    vector<Candidate> bestCodes;\n\n    const int reps = 2;\n\n    for (const auto& book : books) {\n        int B = book.B;\n        int qmax = 100 / B;\n        auto coarseQs = q_candidates(qmax);\n\n        double localBestScore = -1.0;\n        int localBestQ = -1;\n\n        set<int> evaluated;\n        auto try_q = [&](int q) {\n            if (q < 1 || q > qmax) return;\n            if (!evaluated.insert(q).second) return;\n\n            double sc = estimate_proxy_score(book.codes, B, q, M, eps, reps);\n            int N = B * q;\n            if (sc > localBestScore + 1e-15 ||\n                (abs(sc - localBestScore) <= 1e-15 && (localBestQ == -1 || N < B * localBestQ))) {\n                localBestScore = sc;\n                localBestQ = q;\n            }\n        };\n\n        for (int q : coarseQs) try_q(q);\n        for (int q = localBestQ - 2; q <= localBestQ + 2; q++) try_q(q);\n\n        int N = B * localBestQ;\n        if (localBestScore > bestScore + 1e-15 ||\n            (abs(localBestScore - bestScore) <= 1e-15 && (bestN == -1 || N < bestN))) {\n            bestScore = localBestScore;\n            bestB = B;\n            bestQ = localBestQ;\n            bestN = N;\n            bestCodes = book.codes;\n        }\n    }\n\n    if (bestB == -1) {\n        // fallback, should never happen\n        bestB = Bmin;\n        bestQ = 1;\n        bestN = bestB;\n        auto cands = generate_partitions(bestB);\n        bestCodes = select_codewords(cands, M);\n    }\n\n    const int N = bestB * bestQ;\n\n    vector<string> graphStrs(M);\n    vector<vector<double>> expDeg(M);\n    for (int i = 0; i < M; i++) {\n        graphStrs[i] = build_graph_string(bestCodes[i].parts, bestQ);\n        expDeg[i] = build_expected_degree_vector(bestCodes[i].parts, bestQ, eps);\n    }\n\n    cout << N << '\\n';\n    for (int i = 0; i < M; i++) {\n        cout << graphStrs[i] << '\\n';\n    }\n    cout.flush();\n\n    for (int query = 0; query < 100; query++) {\n        string H;\n        cin >> H;\n        if (!cin) return 0;\n\n        vector<int> deg(N, 0);\n        int pos = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                if (H[pos++] == '1') {\n                    deg[i]++;\n                    deg[j]++;\n                }\n            }\n        }\n        sort(deg.begin(), deg.end());\n\n        int ans = 0;\n        double bestS = 1e100;\n        for (int k = 0; k < M; k++) {\n            const auto& mu = expDeg[k];\n            double s = 0.0;\n            for (int i = 0; i < N; i++) {\n                double d = deg[i] - mu[i];\n                s += d * d;\n                if (s >= bestS) break;\n            }\n            if (s < bestS) {\n                bestS = s;\n                ans = k;\n            }\n        }\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x += 0x9e3779b97f4a7c15ull;\n        uint64_t z = x;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& a) {\n        for (int i = (int)a.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(a[i], a[j]);\n        }\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n    double mx, my;\n};\n\nstruct Adj {\n    int to, eid;\n};\n\nstruct PairW {\n    int a, b;\n    double w;\n};\n\nstruct State {\n    vector<int> day;       // size M\n    vector<int> cnt;       // size D\n    vector<double> load;   // normalized importance load per day\n    vector<double> same;   // size M*D, same[e*D+d] = conflict sum if e put on d\n};\n\nclass Solver {\n    static constexpr ll INF = (1LL << 60);\n    static constexpr ll UNREACH = 1000000000LL;\n    static constexpr double PI = 3.14159265358979323846;\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Adj>> g;\n    vector<pair<int,int>> pos;\n    vector<vector<int>> incident;\n    vector<int> degv;\n\n    double centroidX = 0.0, centroidY = 0.0;\n\n    vector<int> sources;\n    int S = 0;\n    vector<vector<ll>> baseDist; // S x N\n\n    vector<double> imp, impN;\n    vector<PairW> conflicts;\n    vector<vector<pair<int,double>>> neigh;\n    vector<double> neighSum;\n    double targetCnt = 0.0;\n    double targetLoad = 0.0;\n\n    chrono::steady_clock::time_point start_time;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    inline double& SAME(State& st, int e, int d) {\n        return st.same[(size_t)e * D + d];\n    }\n    inline double SAMEC(const State& st, int e, int d) const {\n        return st.same[(size_t)e * D + d];\n    }\n\n    void dijkstra_internal(int src, int banDay, const vector<int>& day,\n                           vector<ll>& dist,\n                           vector<int>* parentV = nullptr,\n                           vector<int>* parentE = nullptr) {\n        dist.assign(N, INF);\n        if (parentV) parentV->assign(N, -1);\n        if (parentE) parentE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n\n            for (const auto& a : g[v]) {\n                if (banDay >= 0 && day[a.eid] == banDay) continue;\n                int to = a.to;\n                ll nd = cd + edges[a.eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parentV) (*parentV)[to] = v;\n                    if (parentE) (*parentE)[to] = a.eid;\n                    pq.push({nd, to});\n                } else if (parentV && nd == dist[to]) {\n                    if ((*parentE)[to] == -1 || a.eid < (*parentE)[to]) {\n                        (*parentV)[to] = v;\n                        (*parentE)[to] = a.eid;\n                    }\n                }\n            }\n        }\n    }\n\n    void choose_sources() {\n        S = min(12, N);\n\n        // first source near centroid\n        int first = 0;\n        double best = 1e100;\n        for (int i = 0; i < N; ++i) {\n            double dx = pos[i].first - centroidX;\n            double dy = pos[i].second - centroidY;\n            double d2 = dx * dx + dy * dy;\n            if (d2 < best) {\n                best = d2;\n                first = i;\n            }\n        }\n\n        sources.clear();\n        vector<double> minD2(N, 1e100);\n\n        int cur = first;\n        for (int t = 0; t < S; ++t) {\n            sources.push_back(cur);\n            for (int i = 0; i < N; ++i) {\n                double dx = pos[i].first - pos[cur].first;\n                double dy = pos[i].second - pos[cur].second;\n                double d2 = dx * dx + dy * dy;\n                if (d2 < minD2[i]) minD2[i] = d2;\n            }\n            int nxt = -1;\n            double farv = -1.0;\n            for (int i = 0; i < N; ++i) {\n                bool used = false;\n                for (int s : sources) if (s == i) { used = true; break; }\n                if (used) continue;\n                if (minD2[i] > farv) {\n                    farv = minD2[i];\n                    nxt = i;\n                }\n            }\n            if (nxt == -1) break;\n            cur = nxt;\n        }\n        S = (int)sources.size();\n    }\n\n    void compute_importance() {\n        choose_sources();\n        baseDist.assign(S, vector<ll>(N));\n\n        double avgw = 0.0;\n        for (auto& e : edges) avgw += e.w;\n        avgw /= M;\n\n        vector<double> usage(M, 0.0);\n        vector<ll> dist;\n        vector<int> pv, pe;\n\n        vector<int> emptyDay; // banDay < 0 => ignored\n\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, -1, emptyDay, dist, &pv, &pe);\n            baseDist[si] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sub(N, 1);\n            for (int v : ord) {\n                if (v == src) continue;\n                if (pe[v] != -1) {\n                    usage[pe[v]] += sub[v];\n                    sub[pv[v]] += sub[v];\n                }\n            }\n        }\n\n        imp.assign(M, 1.0);\n        for (int e = 0; e < M; ++e) {\n            double wf = sqrt((double)edges[e].w / avgw);\n            imp[e] = sqrt(1.0 + usage[e]) * (0.7 + 0.3 * wf);\n        }\n\n        double avgImp = 0.0;\n        for (double x : imp) avgImp += x;\n        avgImp /= M;\n\n        impN.resize(M);\n        for (int e = 0; e < M; ++e) impN[e] = imp[e] / avgImp;\n\n        targetCnt = (double)M / D;\n        double sumImpN = 0.0;\n        for (double x : impN) sumImpN += x;\n        targetLoad = sumImpN / D;\n    }\n\n    void build_conflicts() {\n        struct Tmp {\n            int a, b;\n            double w;\n        };\n        vector<Tmp> tmp;\n        tmp.reserve(200000);\n\n        // strong conflicts for edges sharing a vertex\n        for (int v = 0; v < N; ++v) {\n            auto& inc = incident[v];\n            int deg = (int)inc.size();\n            double lowFactor = 1.0 + 0.8 * max(0, 5 - deg); // deg2 -> strong\n            for (int i = 0; i < deg; ++i) {\n                for (int j = i + 1; j < deg; ++j) {\n                    int a = inc[i], b = inc[j];\n                    if (a > b) swap(a, b);\n                    double w = 40.0 * lowFactor * (0.7 + 0.15 * (impN[a] + impN[b]));\n                    tmp.push_back({a, b, w});\n                }\n            }\n        }\n\n        // medium conflicts for spatially close edges\n        const double R = 110.0;\n        const double R2 = R * R;\n        const int CELL = 110;\n        const int G = 1000 / CELL + 4;\n\n        auto cell_id = [&](int x, int y) {\n            return x * G + y;\n        };\n\n        vector<vector<int>> cells(G * G);\n        for (int e = 0; e < M; ++e) {\n            int cx = min(G - 1, max(0, (int)(edges[e].mx / CELL)));\n            int cy = min(G - 1, max(0, (int)(edges[e].my / CELL)));\n            cells[cell_id(cx, cy)].push_back(e);\n        }\n\n        auto share_vertex = [&](int a, int b) -> bool {\n            const auto& A = edges[a];\n            const auto& B = edges[b];\n            return A.u == B.u || A.u == B.v || A.v == B.u || A.v == B.v;\n        };\n\n        for (int x = 0; x < G; ++x) {\n            for (int y = 0; y < G; ++y) {\n                int id1 = cell_id(x, y);\n                for (int nx = max(0, x - 1); nx <= min(G - 1, x + 1); ++nx) {\n                    for (int ny = max(0, y - 1); ny <= min(G - 1, y + 1); ++ny) {\n                        if (nx < x || (nx == x && ny < y)) continue;\n                        int id2 = cell_id(nx, ny);\n                        const auto& c1 = cells[id1];\n                        const auto& c2 = cells[id2];\n                        if (id1 == id2) {\n                            for (int i = 0; i < (int)c1.size(); ++i) {\n                                for (int j = i + 1; j < (int)c1.size(); ++j) {\n                                    int a = c1[i], b = c1[j];\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        if (a > b) swap(a, b);\n                                        tmp.push_back({a, b, w});\n                                    }\n                                }\n                            }\n                        } else {\n                            for (int a : c1) {\n                                for (int b : c2) {\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        int x1 = a, x2 = b;\n                                        if (x1 > x2) swap(x1, x2);\n                                        tmp.push_back({x1, x2, w});\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        sort(tmp.begin(), tmp.end(), [&](const Tmp& p, const Tmp& q) {\n            if (p.a != q.a) return p.a < q.a;\n            return p.b < q.b;\n        });\n\n        conflicts.clear();\n        for (int i = 0; i < (int)tmp.size(); ) {\n            int j = i + 1;\n            double sw = tmp[i].w;\n            while (j < (int)tmp.size() && tmp[j].a == tmp[i].a && tmp[j].b == tmp[i].b) {\n                sw += tmp[j].w;\n                ++j;\n            }\n            conflicts.push_back({tmp[i].a, tmp[i].b, sw});\n            i = j;\n        }\n\n        neigh.assign(M, {});\n        neighSum.assign(M, 0.0);\n        for (auto& p : conflicts) {\n            neigh[p.a].push_back({p.b, p.w});\n            neigh[p.b].push_back({p.a, p.w});\n            neighSum[p.a] += p.w;\n            neighSum[p.b] += p.w;\n        }\n    }\n\n    inline double add_cost(int cnt, double load, double ie, double lc, double li) const {\n        double dc = (cnt + 1 - targetCnt) * (cnt + 1 - targetCnt) - (cnt - targetCnt) * (cnt - targetCnt);\n        double dl = (load + ie - targetLoad) * (load + ie - targetLoad) - (load - targetLoad) * (load - targetLoad);\n        return lc * dc + li * dl;\n    }\n\n    inline double move_delta_proxy(const State& st, int e, int b, double lc, double li) const {\n        int a = st.day[e];\n        if (a == b) return 0.0;\n        if (st.cnt[b] >= K) return 1e100;\n\n        double pairDelta = SAMEC(st, e, b) - SAMEC(st, e, a);\n\n        double dc =\n            (st.cnt[a] - 1 - targetCnt) * (st.cnt[a] - 1 - targetCnt) +\n            (st.cnt[b] + 1 - targetCnt) * (st.cnt[b] + 1 - targetCnt) -\n            (st.cnt[a] - targetCnt) * (st.cnt[a] - targetCnt) -\n            (st.cnt[b] - targetCnt) * (st.cnt[b] - targetCnt);\n\n        double ie = impN[e];\n        double dl =\n            (st.load[a] - ie - targetLoad) * (st.load[a] - ie - targetLoad) +\n            (st.load[b] + ie - targetLoad) * (st.load[b] + ie - targetLoad) -\n            (st.load[a] - targetLoad) * (st.load[a] - targetLoad) -\n            (st.load[b] - targetLoad) * (st.load[b] - targetLoad);\n\n        return pairDelta + lc * dc + li * dl;\n    }\n\n    void apply_move(State& st, int e, int b) {\n        int a = st.day[e];\n        if (a == b) return;\n        st.cnt[a]--;\n        st.cnt[b]++;\n        st.load[a] -= impN[e];\n        st.load[b] += impN[e];\n\n        for (auto [f, w] : neigh[e]) {\n            SAME(st, f, a) -= w;\n            SAME(st, f, b) += w;\n        }\n        st.day[e] = b;\n    }\n\n    State build_state(const vector<int>& day) {\n        State st;\n        st.day = day;\n        st.cnt.assign(D, 0);\n        st.load.assign(D, 0.0);\n\n        for (int e = 0; e < M; ++e) {\n            st.cnt[day[e]]++;\n            st.load[day[e]] += impN[e];\n        }\n\n        st.same.assign((size_t)M * D, 0.0);\n        for (auto& p : conflicts) {\n            SAME(st, p.a, st.day[p.b]) += p.w;\n            SAME(st, p.b, st.day[p.a]) += p.w;\n        }\n        return st;\n    }\n\n    vector<int> construct_initial(int type, RNG& rng, double lc, double li) {\n        vector<int> order;\n        order.reserve(M);\n        vector<int> pref(M, -1);\n\n        if (type == 0) {\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = neighSum[e] + 5.0 * impN[e] + 3.0 * rng.next_double();\n                arr.push_back({-key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n        } else if (type == 1) {\n            double th = rng.next_double() * 2.0 * PI;\n            double cs = cos(th), sn = sin(th);\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = edges[e].mx * cs + edges[e].my * sn + 1e-6 * rng.next_double();\n                arr.push_back({key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        } else {\n            double shift = rng.next_double() * 2.0 * PI;\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double ang = atan2(edges[e].my - centroidY, edges[e].mx - centroidX) - shift;\n                while (ang < 0) ang += 2.0 * PI;\n                while (ang >= 2.0 * PI) ang -= 2.0 * PI;\n                arr.push_back({ang + 1e-6 * rng.next_double(), e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        }\n\n        double prefPenalty = 8.0 + 6.0 * rng.next_double();\n\n        vector<int> day(M, -1);\n        vector<int> cnt(D, 0);\n        vector<double> load(D, 0.0);\n        array<double, 32> tmpConf{};\n\n        for (int e : order) {\n            for (int d = 0; d < D; ++d) tmpConf[d] = 0.0;\n            for (auto [f, w] : neigh[e]) {\n                int df = day[f];\n                if (df != -1) tmpConf[df] += w;\n            }\n\n            int bestd = -1;\n            double bestScore = 1e100;\n            int offset = rng.next_int(D);\n\n            for (int zz = 0; zz < D; ++zz) {\n                int d = (offset + zz) % D;\n                if (cnt[d] >= K) continue;\n                double sc = tmpConf[d] + add_cost(cnt[d], load[d], impN[e], lc, li);\n                if (pref[e] != -1 && d != pref[e]) sc += prefPenalty;\n                sc += 1e-7 * rng.next_double();\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestd = d;\n                }\n            }\n\n            if (bestd == -1) {\n                // fallback, should not happen\n                bestd = 0;\n                while (cnt[bestd] >= K) ++bestd;\n            }\n\n            day[e] = bestd;\n            cnt[bestd]++;\n            load[bestd] += impN[e];\n        }\n\n        return day;\n    }\n\n    void proxy_improve(State& st, RNG& rng, double lc, double li) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < 8; ++pass) {\n            rng.shuffle_vec(ord);\n            int moved = 0;\n\n            for (int e : ord) {\n                int a = st.day[e];\n                int bestd = a;\n                double bestDelta = -1e-9;\n\n                int offset = rng.next_int(D);\n                for (int zz = 0; zz < D; ++zz) {\n                    int d = (offset + zz) % D;\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                    }\n                }\n\n                if (bestd != a) {\n                    apply_move(st, e, bestd);\n                    moved++;\n                }\n            }\n\n            if (moved == 0) break;\n            if (elapsed() > 4.5) break;\n        }\n    }\n\n    ll eval_day_cost(int banDay, const vector<int>& day) {\n        ll res = 0;\n        vector<ll> dist;\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, banDay, day, dist, nullptr, nullptr);\n            const auto& bd = baseDist[si];\n            for (int v = 0; v < N; ++v) {\n                if (v == src) continue;\n                ll nd = (dist[v] >= INF / 2 ? UNREACH : dist[v]);\n                res += nd - bd[v];\n            }\n        }\n        return res;\n    }\n\n    ll eval_schedule(const vector<int>& day, const vector<int>& cnt, vector<ll>& dayCost) {\n        dayCost.assign(D, 0);\n        ll total = 0;\n        for (int d = 0; d < D; ++d) {\n            if (cnt[d] == 0) continue;\n            dayCost[d] = eval_day_cost(d, day);\n            total += dayCost[d];\n        }\n        return total;\n    }\n\n    void actual_refine(vector<int>& bestDay, double lc, double li) {\n        State st = build_state(bestDay);\n        vector<ll> dayCost;\n        ll curScore = eval_schedule(st.day, st.cnt, dayCost);\n\n        int accepted = 0;\n        while (elapsed() < 5.45 && accepted < 25) {\n            vector<int> worstOrd(D);\n            iota(worstOrd.begin(), worstOrd.end(), 0);\n            sort(worstOrd.begin(), worstOrd.end(), [&](int a, int b) {\n                return dayCost[a] > dayCost[b];\n            });\n\n            int takeDays = min(3, D);\n            array<int, 32> isTop{};\n            for (int i = 0; i < takeDays; ++i) isTop[worstOrd[i]] = 1;\n\n            vector<pair<double,int>> candEdges;\n            candEdges.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                int d = st.day[e];\n                if (!isTop[d]) continue;\n                double score = SAMEC(st, e, d) + 4.0 * impN[e];\n                candEdges.push_back({-score, e});\n            }\n\n            if (candEdges.empty()) break;\n            sort(candEdges.begin(), candEdges.end());\n            if ((int)candEdges.size() > 50) candEdges.resize(50);\n\n            vector<int> lowOrd(D);\n            iota(lowOrd.begin(), lowOrd.end(), 0);\n            sort(lowOrd.begin(), lowOrd.end(), [&](int a, int b) {\n                return dayCost[a] < dayCost[b];\n            });\n\n            bool moved = false;\n\n            for (auto [negScore, e] : candEdges) {\n                if (elapsed() > 5.45) break;\n\n                int a = st.day[e];\n                vector<pair<double,int>> pd;\n                pd.reserve(D);\n\n                for (int d = 0; d < D; ++d) {\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    pd.push_back({delta, d});\n                }\n                if (pd.empty()) continue;\n\n                sort(pd.begin(), pd.end());\n                vector<int> candDays;\n                for (int i = 0; i < (int)pd.size() && i < 4; ++i) candDays.push_back(pd[i].second);\n                for (int i = 0; i < min(2, D); ++i) {\n                    int d = lowOrd[i];\n                    if (d == a || st.cnt[d] >= K) continue;\n                    bool found = false;\n                    for (int x : candDays) if (x == d) found = true;\n                    if (!found) candDays.push_back(d);\n                }\n\n                ll bestDelta = 0;\n                int bestd = -1;\n                ll bestA = 0, bestB = 0;\n\n                int old = st.day[e];\n                for (int d : candDays) {\n                    st.day[e] = d;\n                    ll na = eval_day_cost(a, st.day);\n                    ll nb = eval_day_cost(d, st.day);\n                    ll delta = (na + nb) - (dayCost[a] + dayCost[d]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                        bestA = na;\n                        bestB = nb;\n                    }\n                }\n                st.day[e] = old;\n\n                if (bestd != -1) {\n                    apply_move(st, e, bestd);\n                    dayCost[a] = bestA;\n                    dayCost[bestd] = bestB;\n                    curScore += bestDelta;\n                    accepted++;\n                    moved = true;\n                    break;\n                }\n            }\n\n            if (!moved) break;\n        }\n\n        bestDay = st.day;\n        (void)curScore;\n    }\n\npublic:\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(N, {});\n        degv.assign(N, 0);\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            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            degv[u]++;\n            degv[v]++;\n        }\n\n        pos.resize(N);\n        for (int i = 0; i < N; ++i) {\n            cin >> pos[i].first >> pos[i].second;\n            centroidX += pos[i].first;\n            centroidY += pos[i].second;\n        }\n        centroidX /= N;\n        centroidY /= N;\n\n        for (int i = 0; i < M; ++i) {\n            edges[i].mx = 0.5 * (pos[edges[i].u].first + pos[edges[i].v].first);\n            edges[i].my = 0.5 * (pos[edges[i].u].second + pos[edges[i].v].second);\n        }\n\n        compute_importance();\n        build_conflicts();\n\n        uint64_t seedBase = 1469598103934665603ull;\n        seedBase ^= (uint64_t)N + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)M + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)D + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)K + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n\n        vector<int> bestDay;\n        ll bestScore = (1LL << 62);\n        double bestLc = 4.5, bestLi = 2.0;\n\n        int runs = 0;\n        while (elapsed() < 3.8 && runs < 12) {\n            RNG rng(seedBase + 1000003ull * (uint64_t)runs + 1234567ull);\n\n            double lc = 3.5 + 2.5 * rng.next_double();\n            double li = 1.5 + 2.0 * rng.next_double();\n\n            int type = runs % 3;\n            vector<int> initDay = construct_initial(type, rng, lc, li);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, lc, li);\n\n            vector<ll> dayCost;\n            ll sc = eval_schedule(st.day, st.cnt, dayCost);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestDay = st.day;\n                bestLc = lc;\n                bestLi = li;\n            }\n            runs++;\n        }\n\n        if (bestDay.empty()) {\n            RNG rng(seedBase);\n            vector<int> initDay = construct_initial(0, rng, 4.5, 2.0);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, 4.5, 2.0);\n            bestDay = st.day;\n        }\n\n        actual_refine(bestDay, bestLc, bestLi);\n\n        for (int i = 0; i < M; ++i) {\n            if (i) cout << ' ';\n            cout << bestDay[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\nstatic constexpr int MAXD = 14;\nstatic constexpr int MAXN = MAXD * MAXD * MAXD;\n\nstruct Comp {\n    vector<int> cells; // flat indices\n    int vol = 0;\n};\n\nstruct Seg {\n    int x, y, z0, len;\n};\n\nstruct SegCmp {\n    bool operator()(const Seg& a, const Seg& b) const {\n        if (a.len != b.len) return a.len < b.len;   // max-heap by len\n        if (a.x != b.x) return a.x > b.x;\n        if (a.y != b.y) return a.y > b.y;\n        return a.z0 > b.z0;\n    }\n};\n\nint D;\nint Ncells;\nstring fstr[2][MAXD], rstr[2][MAXD];\nuint16_t actXMask[2][MAXD], actYMask[2][MAXD];\nvector<int> actXList[2][MAXD], actYList[2][MAXD];\n\nvector<Comp> comps;\n\nchrono::steady_clock::time_point g_start;\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\n\ninline void decode3(int id, int &x, int &y, int &z) {\n    x = id / (D * D);\n    int rem = id % (D * D);\n    y = rem / D;\n    z = rem % D;\n}\n\ntemplate <class Bonus>\nvector<pair<int,int>> assign_caseA(\n    const vector<int>& Xneed,\n    const vector<int>& Yneed,\n    const vector<int>& Yall,\n    Bonus bonus\n) {\n    // |Xneed| >= |Yneed|\n    vector<pair<int,int>> edges;\n    edges.reserve(Xneed.size());\n    int p = (int)Xneed.size();\n    vector<char> usedX(p, 0);\n\n    struct Item {\n        int y, gap, best;\n    };\n    vector<Item> ord;\n    ord.reserve(Yneed.size());\n\n    for (int y : Yneed) {\n        int best1 = -1e9, best2 = -1e9;\n        for (int x : Xneed) {\n            int b = bonus(x, y);\n            if (b > best1) {\n                best2 = best1;\n                best1 = b;\n            } else if (b > best2) {\n                best2 = b;\n            }\n        }\n        int gap = (best2 <= -100000000 ? 1000000 : best1 - best2);\n        ord.push_back({y, gap, best1});\n    }\n    sort(ord.begin(), ord.end(), [&](const Item& a, const Item& b) {\n        if (a.gap != b.gap) return a.gap > b.gap;\n        if (a.best != b.best) return a.best > b.best;\n        return a.y < b.y;\n    });\n\n    for (auto &it : ord) {\n        int choose = -1, bestb = -1e9;\n        for (int i = 0; i < p; i++) if (!usedX[i]) {\n            int b = bonus(Xneed[i], it.y);\n            if (b > bestb || (b == bestb && (choose == -1 || Xneed[i] < Xneed[choose]))) {\n                bestb = b;\n                choose = i;\n            }\n        }\n        if (choose == -1) choose = 0;\n        usedX[choose] = 1;\n        edges.push_back({Xneed[choose], it.y});\n    }\n\n    for (int i = 0; i < p; i++) if (!usedX[i]) {\n        int x = Xneed[i];\n        int besty = Yall[0], bestb = -1e9;\n        for (int y : Yall) {\n            int b = bonus(x, y);\n            if (b > bestb || (b == bestb && y < besty)) {\n                bestb = b;\n                besty = y;\n            }\n        }\n        edges.push_back({x, besty});\n    }\n\n    return edges;\n}\n\ntemplate <class Bonus>\nvector<pair<int,int>> assign_caseB(\n    const vector<int>& Xneed,\n    const vector<int>& Xall,\n    const vector<int>& Yneed,\n    Bonus bonus\n) {\n    // |Xneed| < |Yneed|\n    vector<pair<int,int>> edges;\n    edges.reserve(Yneed.size());\n    int q = (int)Yneed.size();\n    vector<char> usedY(q, 0);\n\n    struct Item {\n        int x, gap, best;\n    };\n    vector<Item> ord;\n    ord.reserve(Xneed.size());\n\n    for (int x : Xneed) {\n        int best1 = -1e9, best2 = -1e9;\n        for (int y : Yneed) {\n            int b = bonus(x, y);\n            if (b > best1) {\n                best2 = best1;\n                best1 = b;\n            } else if (b > best2) {\n                best2 = b;\n            }\n        }\n        int gap = (best2 <= -100000000 ? 1000000 : best1 - best2);\n        ord.push_back({x, gap, best1});\n    }\n    sort(ord.begin(), ord.end(), [&](const Item& a, const Item& b) {\n        if (a.gap != b.gap) return a.gap > b.gap;\n        if (a.best != b.best) return a.best > b.best;\n        return a.x < b.x;\n    });\n\n    for (auto &it : ord) {\n        int choose = -1, bestb = -1e9;\n        for (int i = 0; i < q; i++) if (!usedY[i]) {\n            int b = bonus(it.x, Yneed[i]);\n            if (b > bestb || (b == bestb && (choose == -1 || Yneed[i] < Yneed[choose]))) {\n                bestb = b;\n                choose = i;\n            }\n        }\n        if (choose == -1) choose = 0;\n        usedY[choose] = 1;\n        edges.push_back({it.x, Yneed[choose]});\n    }\n\n    for (int i = 0; i < q; i++) if (!usedY[i]) {\n        int y = Yneed[i];\n        int bestx = Xall[0], bestb = -1e9;\n        for (int x : Xall) {\n            int b = bonus(x, y);\n            if (b > bestb || (b == bestb && x < bestx)) {\n                bestb = b;\n                bestx = x;\n            }\n        }\n        edges.push_back({bestx, y});\n    }\n\n    return edges;\n}\n\nvoid extract_segments(const array<uint8_t, MAXN>& occ, vector<Seg>& segs) {\n    segs.clear();\n    for (int x = 0; x < D; x++) {\n        for (int y = 0; y < D; y++) {\n            int z = 0;\n            while (z < D) {\n                while (z < D && !occ[idx3(x,y,z)]) z++;\n                if (z == D) break;\n                int z0 = z;\n                while (z < D && occ[idx3(x,y,z)]) z++;\n                segs.push_back({x, y, z0, z - z0});\n            }\n        }\n    }\n}\n\nlong double match_score_only(const array<uint8_t, MAXN>& occ1, const array<uint8_t, MAXN>& occ2) {\n    vector<Seg> s1, s2;\n    extract_segments(occ1, s1);\n    extract_segments(occ2, s2);\n\n    priority_queue<Seg, vector<Seg>, SegCmp> pq1, pq2;\n    for (auto &s : s1) pq1.push(s);\n    for (auto &s : s2) pq2.push(s);\n\n    long double sc = 0.0L;\n    long long exclusive = 0;\n\n    while (!pq1.empty() && !pq2.empty()) {\n        Seg a = pq1.top(); pq1.pop();\n        Seg b = pq2.top(); pq2.pop();\n        int m = min(a.len, b.len);\n        sc += 1.0L / (long double)m;\n        if (a.len > m) {\n            a.z0 += m;\n            a.len -= m;\n            pq1.push(a);\n        }\n        if (b.len > m) {\n            b.z0 += m;\n            b.len -= m;\n            pq2.push(b);\n        }\n    }\n    while (!pq1.empty()) {\n        exclusive += pq1.top().len;\n        pq1.pop();\n    }\n    while (!pq2.empty()) {\n        exclusive += pq2.top().len;\n        pq2.pop();\n    }\n    sc += (long double)exclusive;\n    return sc;\n}\n\nlong double build_mode_score(\n    const vector<char>& keep,\n    int mode, // 0=fwd, 1=bwd, 2=none\n    array<array<uint8_t, MAXN>, 2>* saveExtra = nullptr\n) {\n    // core info\n    uint16_t covX[MAXD] = {};\n    uint16_t covY[MAXD] = {};\n    uint16_t coreRow[MAXD][MAXD];\n    memset(coreRow, 0, sizeof(coreRow));\n\n    long double score = 0.0L;\n\n    for (int cid = 0; cid < (int)comps.size(); cid++) {\n        if (!keep[cid]) continue;\n        score += 1.0L / (long double)comps[cid].vol;\n        for (int id : comps[cid].cells) {\n            int x, y, z;\n            decode3(id, x, y, z);\n            covX[z] |= (uint16_t(1) << x);\n            covY[z] |= (uint16_t(1) << y);\n            coreRow[z][x] |= (uint16_t(1) << y);\n        }\n    }\n\n    uint16_t needXMask[2][MAXD];\n    uint16_t needYMask[2][MAXD];\n    uint16_t maskD = (uint16_t)((1u << D) - 1);\n\n    for (int obj = 0; obj < 2; obj++) {\n        for (int z = 0; z < D; z++) {\n            needXMask[obj][z] = actXMask[obj][z] & (uint16_t)(~covX[z] & maskD);\n            needYMask[obj][z] = actYMask[obj][z] & (uint16_t)(~covY[z] & maskD);\n        }\n    }\n\n    array<array<uint8_t, MAXN>, 2> extra;\n    extra[0].fill(0);\n    extra[1].fill(0);\n\n    const int BPREV = 100;\n    const int BNEXT = 1;\n\n    for (int obj = 0; obj < 2; obj++) {\n        bool prev[MAXD][MAXD];\n        memset(prev, 0, sizeof(prev));\n\n        int zStart = 0, zEnd = D, zStep = 1;\n        if (mode == 1) { zStart = D - 1; zEnd = -1; zStep = -1; }\n\n        for (int z = zStart; z != zEnd; z += zStep) {\n            const auto& Xall = actXList[obj][z];\n            const auto& Yall = actYList[obj][z];\n\n            vector<int> Xneed, Yneed;\n            for (int x : Xall) if ((needXMask[obj][z] >> x) & 1) Xneed.push_back(x);\n            for (int y : Yall) if ((needYMask[obj][z] >> y) & 1) Yneed.push_back(y);\n\n            bool cur[MAXD][MAXD];\n            memset(cur, 0, sizeof(cur));\n\n            int nextz = -100;\n            if (mode == 0) nextz = z + 1;\n            else if (mode == 1) nextz = z - 1;\n\n            auto bonus = [&](int x, int y) -> int {\n                if (mode == 2) return 0;\n                int b = 0;\n                if (prev[x][y]) b += BPREV;\n                if (0 <= nextz && nextz < D) {\n                    bool active = ((actXMask[obj][nextz] >> x) & 1) && ((actYMask[obj][nextz] >> y) & 1);\n                    bool isCore = (coreRow[nextz][x] >> y) & 1;\n                    bool needed = ((needXMask[obj][nextz] >> x) & 1) || ((needYMask[obj][nextz] >> y) & 1);\n                    if (active && !isCore && needed) b += BNEXT;\n                }\n                return b;\n            };\n\n            vector<pair<int,int>> edges;\n            if ((int)Xneed.size() >= (int)Yneed.size()) {\n                edges = assign_caseA(Xneed, Yneed, Yall, bonus);\n            } else {\n                edges = assign_caseB(Xneed, Xall, Yneed, bonus);\n            }\n\n            for (auto [x, y] : edges) {\n                extra[obj][idx3(x,y,z)] = 1;\n                cur[x][y] = true;\n            }\n            memcpy(prev, cur, sizeof(prev));\n        }\n    }\n\n    score += match_score_only(extra[0], extra[1]);\n\n    if (saveExtra) {\n        *saveExtra = extra;\n    }\n    return score;\n}\n\npair<long double,int> evaluate_keep(const vector<char>& keep) {\n    long double best = 1e100L;\n    int bestMode = 0;\n    for (int mode = 0; mode < 3; mode++) {\n        long double sc = build_mode_score(keep, mode, nullptr);\n        if (sc < best) {\n            best = sc;\n            bestMode = mode;\n        }\n    }\n    return {best, bestMode};\n}\n\nvoid build_full_common_components() {\n    vector<uint8_t> common(Ncells, 0);\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 (fstr[0][z][x] == '1' && fstr[1][z][x] == '1' &&\n                    rstr[0][z][y] == '1' && rstr[1][z][y] == '1') {\n                    common[idx3(x,y,z)] = 1;\n                }\n            }\n        }\n    }\n\n    vector<uint8_t> vis(Ncells, 0);\n    int dx[6] = {1,-1,0,0,0,0};\n    int dy[6] = {0,0,1,-1,0,0};\n    int dz[6] = {0,0,0,0,1,-1};\n\n    for (int id = 0; id < Ncells; id++) {\n        if (!common[id] || vis[id]) continue;\n        Comp c;\n        queue<int> q;\n        q.push(id);\n        vis[id] = 1;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (common[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        comps.push_back(std::move(c));\n    }\n}\n\nvoid assign_final_labels(\n    const vector<char>& keep,\n    const array<array<uint8_t, MAXN>, 2>& extra,\n    array<int, MAXN>& out1,\n    array<int, MAXN>& out2,\n    int& nblocks\n) {\n    out1.fill(0);\n    out2.fill(0);\n    nblocks = 0;\n\n    // Shared core components\n    for (int cid = 0; cid < (int)comps.size(); cid++) {\n        if (!keep[cid]) continue;\n        ++nblocks;\n        for (int id : comps[cid].cells) {\n            out1[id] = nblocks;\n            out2[id] = nblocks;\n        }\n    }\n\n    // Extra bars\n    vector<Seg> s1, s2;\n    extract_segments(extra[0], s1);\n    extract_segments(extra[1], s2);\n\n    priority_queue<Seg, vector<Seg>, SegCmp> pq1, pq2;\n    for (auto &s : s1) pq1.push(s);\n    for (auto &s : s2) pq2.push(s);\n\n    auto fill_seg = [&](array<int, MAXN>& out, const Seg& s, int len, int label) {\n        for (int t = 0; t < len; t++) {\n            out[idx3(s.x, s.y, s.z0 + t)] = label;\n        }\n    };\n\n    while (!pq1.empty() && !pq2.empty()) {\n        Seg a = pq1.top(); pq1.pop();\n        Seg b = pq2.top(); pq2.pop();\n        int m = min(a.len, b.len);\n        ++nblocks;\n        fill_seg(out1, a, m, nblocks);\n        fill_seg(out2, b, m, nblocks);\n\n        if (a.len > m) {\n            a.z0 += m;\n            a.len -= m;\n            pq1.push(a);\n        }\n        if (b.len > m) {\n            b.z0 += m;\n            b.len -= m;\n            pq2.push(b);\n        }\n    }\n\n    while (!pq1.empty()) {\n        Seg a = pq1.top(); pq1.pop();\n        ++nblocks;\n        fill_seg(out1, a, a.len, nblocks);\n    }\n    while (!pq2.empty()) {\n        Seg b = pq2.top(); pq2.pop();\n        ++nblocks;\n        fill_seg(out2, b, b.len, nblocks);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> D;\n    Ncells = D * D * D;\n\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) cin >> fstr[i][z];\n        for (int z = 0; z < D; z++) cin >> rstr[i][z];\n    }\n\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) {\n            actXMask[i][z] = 0;\n            actYMask[i][z] = 0;\n            actXList[i][z].clear();\n            actYList[i][z].clear();\n            for (int x = 0; x < D; x++) {\n                if (fstr[i][z][x] == '1') {\n                    actXMask[i][z] |= (uint16_t(1) << x);\n                    actXList[i][z].push_back(x);\n                }\n            }\n            for (int y = 0; y < D; y++) {\n                if (rstr[i][z][y] == '1') {\n                    actYMask[i][z] |= (uint16_t(1) << y);\n                    actYList[i][z].push_back(y);\n                }\n            }\n        }\n    }\n\n    build_full_common_components();\n\n    vector<char> bestKeep(comps.size(), 0);\n    long double bestScore = 1e100L;\n    int bestMode = 0;\n\n    if ((int)comps.size() <= 12) {\n        int C = (int)comps.size();\n        int LIM = 1 << C;\n        vector<char> keep(C);\n        for (int mask = 0; mask < LIM; mask++) {\n            if (elapsed_sec() > 5.3) break;\n            for (int i = 0; i < C; i++) keep[i] = (mask >> i) & 1;\n            auto [sc, md] = evaluate_keep(keep);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMode = md;\n                bestKeep = keep;\n            }\n        }\n    } else {\n        vector<int> thresholds = {0, 1, 2, 3, 4, 5, 8, (int)1e9};\n        vector<char> keep(comps.size(), 0);\n\n        for (int t : thresholds) {\n            if (elapsed_sec() > 5.0) break;\n            for (int i = 0; i < (int)comps.size(); i++) {\n                keep[i] = (comps[i].vol > t);\n            }\n            auto [sc, md] = evaluate_keep(keep);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMode = md;\n                bestKeep = keep;\n            }\n        }\n\n        vector<int> ord(comps.size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (comps[a].vol != comps[b].vol) return comps[a].vol < comps[b].vol;\n            return a < b;\n        });\n        if ((int)ord.size() > 120) ord.resize(120);\n\n        vector<char> curKeep = bestKeep;\n        long double curScore = bestScore;\n        int curMode = bestMode;\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool improved = false;\n            for (int cid : ord) {\n                if (elapsed_sec() > 5.5) break;\n                curKeep[cid] ^= 1;\n                auto [sc, md] = evaluate_keep(curKeep);\n                if (sc + 1e-15L < curScore) {\n                    curScore = sc;\n                    curMode = md;\n                    improved = true;\n                } else {\n                    curKeep[cid] ^= 1;\n                }\n            }\n            if (!improved) break;\n        }\n\n        bestKeep = curKeep;\n        bestScore = curScore;\n        bestMode = curMode;\n    }\n\n    array<array<uint8_t, MAXN>, 2> bestExtra;\n    build_mode_score(bestKeep, bestMode, &bestExtra);\n\n    array<int, MAXN> out1, out2;\n    int nblocks = 0;\n    assign_final_labels(bestKeep, bestExtra, out1, out2, nblocks);\n\n    cout << nblocks << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out2[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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 leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v;\n    int w;\n};\n\nstruct Candidate {\n    vector<int> P;\n    vector<char> B;\n    int covered = -1;\n    long long cost = (1LL << 62);\n};\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> B;\n};\n\nclass Solver {\npublic:\n    int N, M, K;\n    vector<int> xs, ys;\n    vector<Edge> edges;\n    vector<int> as, bs;\n\n    vector<vector<int>> req; // req[i][k] = minimum power to cover resident k, or 5001\n    vector<vector<pair<int,int>>> lists; // (required power, resident id), sorted\n\n    vector<vector<long long>> sp;\n    vector<vector<int>> nxt;\n    vector<vector<int>> eidMat;\n    vector<vector<int>> incident;\n\n    chrono::steady_clock::time_point t0;\n\n    static constexpr long long INF64 = (1LL << 60);\n\n    void input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> K;\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n        edges.resize(M);\n        incident.assign(N, {});\n        eidMat.assign(N, vector<int>(N, -1));\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, v, w};\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            eidMat[u][v] = eidMat[v][u] = i;\n        }\n\n        as.resize(K);\n        bs.resize(K);\n        for (int k = 0; k < K; k++) cin >> as[k] >> bs[k];\n    }\n\n    static int ceil_sqrt_ll(long long x) {\n        long long r = sqrt((long double)x);\n        while (r * r < x) ++r;\n        while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n        return (int)r;\n    }\n\n    void precompute() {\n        // req + sorted lists\n        req.assign(N, vector<int>(K, 5001));\n        lists.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            lists[i].reserve(K / 4);\n            for (int k = 0; k < K; k++) {\n                long long dx = (long long)xs[i] - as[k];\n                long long dy = (long long)ys[i] - bs[k];\n                long long d2 = dx * dx + dy * dy;\n                int r = ceil_sqrt_ll(d2);\n                if (r <= 5000) {\n                    req[i][k] = r;\n                    lists[i].push_back({r, k});\n                }\n            }\n            sort(lists[i].begin(), lists[i].end());\n        }\n\n        // Floyd-Warshall\n        sp.assign(N, vector<long long>(N, INF64));\n        nxt.assign(N, vector<int>(N, -1));\n        for (int i = 0; i < N; i++) {\n            sp[i][i] = 0;\n            nxt[i][i] = i;\n        }\n        for (int e = 0; e < M; e++) {\n            auto [u, v, w] = edges[e];\n            if ((long long)w < sp[u][v]) {\n                sp[u][v] = sp[v][u] = w;\n                nxt[u][v] = v;\n                nxt[v][u] = u;\n            }\n        }\n        for (int k = 0; k < N; k++) {\n            for (int i = 0; i < N; i++) if (sp[i][k] < INF64) {\n                for (int j = 0; j < N; j++) if (sp[k][j] < INF64) {\n                    long long nd = sp[i][k] + sp[k][j];\n                    if (nd < sp[i][j]) {\n                        sp[i][j] = nd;\n                        nxt[i][j] = nxt[i][k];\n                    }\n                }\n            }\n        }\n\n        t0 = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        auto t = chrono::steady_clock::now();\n        return chrono::duration<double>(t - t0).count();\n    }\n\n    vector<int> reconstruct_path_vertices(int s, int t) const {\n        vector<int> path;\n        if (nxt[s][t] == -1) return path;\n        int cur = s;\n        path.push_back(cur);\n        while (cur != t) {\n            cur = nxt[cur][t];\n            path.push_back(cur);\n        }\n        return path;\n    }\n\n    vector<long double> make_gain_table(long double gamma) const {\n        vector<long double> gain(K + 1, 0);\n        if (fabsl(gamma - 1.0L) < 1e-18L) {\n            for (int i = 1; i <= K; i++) gain[i] = (long double)i;\n        } else {\n            for (int i = 1; i <= K; i++) gain[i] = powl((long double)i, gamma);\n        }\n        return gain;\n    }\n\n    void recompute_nearest_tree(\n        const vector<char>& inTree,\n        vector<long long>& distToTree,\n        vector<int>& nearTree\n    ) const {\n        distToTree.assign(N, INF64);\n        nearTree.assign(N, -1);\n        for (int i = 0; i < N; i++) {\n            if (inTree[i]) {\n                distToTree[i] = 0;\n                nearTree[i] = i;\n                continue;\n            }\n            long long best = INF64;\n            int bestv = -1;\n            for (int v = 0; v < N; v++) if (inTree[v]) {\n                if (sp[v][i] < best) {\n                    best = sp[v][i];\n                    bestv = v;\n                }\n            }\n            distToTree[i] = best;\n            nearTree[i] = bestv;\n        }\n    }\n\n    InitialState greedy_initial(long double alpha, long double gamma) {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P(N, 0);\n        vector<int> curPos(N, 0);\n        vector<char> covered(K, 0);\n        vector<char> usedEdge(M, 0);\n        vector<char> inTree(N, 0);\n        inTree[0] = 1;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        int rem = K;\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                long double conn = inTree[i] ? 0.0L : alpha * (long double)distToTree[i];\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (!covered[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq) + conn;\n                    long double metric = num / gain[newcov];\n\n                    bool better = false;\n                    if (metric < bestMetric - 1e-18L) better = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) better = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) better = true;\n                    }\n                    if (better) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            if (!inTree[bestStation]) {\n                int from = nearTree[bestStation];\n                auto path = reconstruct_path_vertices(from, bestStation);\n\n                // Add only the suffix after the last already-in-tree vertex to avoid cycles.\n                int lastTreeIdx = 0;\n                for (int i = 0; i < (int)path.size(); i++) {\n                    if (inTree[path[i]]) lastTreeIdx = i;\n                }\n                for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                    int u = path[i], v = path[i + 1];\n                    int eid = eidMat[u][v];\n                    if (eid >= 0) usedEdge[eid] = 1;\n                    inTree[u] = 1;\n                    inTree[v] = 1;\n                }\n                recompute_nearest_tree(inTree, distToTree, nearTree);\n            }\n\n            int oldPos = curPos[bestStation];\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = oldPos;\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (!covered[rid]) {\n                    covered[rid] = 1;\n                    --rem;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return {P, usedEdge};\n    }\n\n    vector<int> greedy_on_allowed(const vector<char>& allowed, long double gamma) {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P(N, 0);\n        vector<int> curPos(N, 0);\n        vector<char> covered(K, 0);\n        int rem = K;\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                if (!allowed[i]) continue;\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (!covered[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq);\n                    long double metric = num / gain[newcov];\n\n                    bool better = false;\n                    if (metric < bestMetric - 1e-18L) better = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) better = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) better = true;\n                    }\n                    if (better) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            int oldPos = curPos[bestStation];\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = oldPos;\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (!covered[rid]) {\n                    covered[rid] = 1;\n                    --rem;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return P;\n    }\n\n    void reduce_powers(vector<int>& P, const vector<char>& allowed) {\n        while (true) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) {\n                if (allowed[i] && P[i] > 0) active.push_back(i);\n            }\n            sort(active.begin(), active.end(), [&](int a, int b) {\n                if (P[a] != P[b]) return P[a] > P[b];\n                return a < b;\n            });\n\n            bool changed = false;\n            for (int i : active) {\n                int newP = 0;\n                for (const auto& [d, rid] : lists[i]) {\n                    if (d > P[i]) break;\n                    bool other = false;\n                    for (int j : active) {\n                        if (j == i || P[j] == 0) continue;\n                        if (req[j][rid] <= P[j]) {\n                            other = true;\n                            break;\n                        }\n                    }\n                    if (!other) newP = d;\n                }\n                if (newP < P[i]) {\n                    P[i] = newP;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    vector<char> terminals_from_P(const vector<int>& P) const {\n        vector<char> term(N, 0);\n        term[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) term[i] = 1;\n        return term;\n    }\n\n    vector<char> build_tree_from_terminals(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n\n        vector<int> ids;\n        ids.push_back(0);\n        for (int i = 1; i < N; i++) if (terminal[i]) ids.push_back(i);\n\n        int T = (int)ids.size();\n        if (T <= 1) return used;\n\n        // MST on metric closure by Prim\n        vector<long long> minD(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> vis(T, 0);\n        minD[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            for (int i = 0; i < T; i++) {\n                if (!vis[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            vis[v] = 1;\n            for (int u = 0; u < T; u++) if (!vis[u]) {\n                if (sp[ids[v]][ids[u]] < minD[u]) {\n                    minD[u] = sp[ids[v]][ids[u]];\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<char> cand(M, 0);\n        vector<int> candEdges;\n        for (int i = 1; i < T; i++) {\n            auto path = reconstruct_path_vertices(ids[i], ids[par[i]]);\n            for (int j = 0; j + 1 < (int)path.size(); j++) {\n                int a = path[j], b = path[j + 1];\n                int eid = eidMat[a][b];\n                if (eid >= 0 && !cand[eid]) {\n                    cand[eid] = 1;\n                    candEdges.push_back(eid);\n                }\n            }\n        }\n\n        sort(candEdges.begin(), candEdges.end(), [&](int e1, int e2) {\n            if (edges[e1].w != edges[e2].w) return edges[e1].w < edges[e2].w;\n            return e1 < e2;\n        });\n\n        DSU dsu(N);\n        for (int eid : candEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            if (dsu.merge(u, v)) used[eid] = 1;\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        return used;\n    }\n\n    void prune_nonterminal_leaves(vector<char>& B, const vector<char>& terminal) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n\n        queue<int> q;\n        for (int v = 0; v < N; v++) {\n            if (v != 0 && !terminal[v] && deg[v] == 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            if (v == 0 || terminal[v] || deg[v] != 1) continue;\n\n            int remE = -1, to = -1;\n            for (int eid : incident[v]) if (B[eid]) {\n                remE = eid;\n                to = edges[eid].u ^ edges[eid].v ^ v;\n                break;\n            }\n            if (remE == -1) continue;\n\n            B[remE] = 0;\n            deg[v]--;\n            deg[to]--;\n            if (to != 0 && !terminal[to] && deg[to] == 1) q.push(to);\n        }\n    }\n\n    vector<char> tree_vertices(const vector<char>& B) const {\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 (int eid : incident[v]) if (B[eid]) {\n                int to = edges[eid].u ^ edges[eid].v ^ v;\n                if (!vis[to]) {\n                    vis[to] = 1;\n                    q.push(to);\n                }\n            }\n        }\n        return vis;\n    }\n\n    Candidate make_candidate(const vector<int>& Pin, const vector<char>& Bin) const {\n        vector<int> P = Pin;\n        vector<char> B = Bin;\n\n        // Remove disconnected components not reachable from root.\n        vector<char> reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n        for (int e = 0; e < M; e++) {\n            if (B[e]) {\n                int u = edges[e].u, v = edges[e].v;\n                if (!(reach[u] && reach[v])) B[e] = 0;\n            }\n        }\n\n        // Prune leaves without powered stations.\n        vector<char> terminal(N, 0);\n        terminal[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) terminal[i] = 1;\n        prune_nonterminal_leaves(B, terminal);\n\n        // Recompute reach; zero any now-unreachable power.\n        reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (reach[i] && P[i] > 0) active.push_back(i);\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n\n        long long cost = 0;\n        for (int i = 0; i < N; i++) cost += 1LL * P[i] * P[i];\n        for (int e = 0; e < M; e++) if (B[e]) cost += edges[e].w;\n\n        return {P, B, cov, cost};\n    }\n\n    static bool better(const Candidate& a, const Candidate& b, int K) {\n        if (a.covered != b.covered) return a.covered > b.covered;\n        if (a.covered == K) return a.cost < b.cost;\n        return a.cost < b.cost;\n    }\n\n    Candidate solve_variant(long double alpha, long double gammaInit) {\n        Candidate bestLocal;\n\n        auto consider = [&](const vector<int>& P, const vector<char>& B) {\n            Candidate c = make_candidate(P, B);\n            if (better(c, bestLocal, K)) bestLocal = std::move(c);\n        };\n\n        // 1) Initial connected greedy\n        InitialState init = greedy_initial(alpha, gammaInit);\n        consider(init.P, init.B);\n\n        vector<char> B0m = build_tree_from_terminals(terminals_from_P(init.P));\n        consider(init.P, B0m);\n\n        // 2) Re-optimize powers on current initial tree\n        vector<char> allowed0 = tree_vertices(init.B);\n        vector<int> P1 = greedy_on_allowed(allowed0, 1.0L);\n        reduce_powers(P1, allowed0);\n        consider(P1, init.B);\n\n        vector<char> B1 = build_tree_from_terminals(terminals_from_P(P1));\n        consider(P1, B1);\n\n        // 3) One more round on the reconnected tree\n        vector<char> allowed1 = tree_vertices(B1);\n        vector<int> P2 = greedy_on_allowed(allowed1, 1.0L);\n        reduce_powers(P2, allowed1);\n        consider(P2, B1);\n\n        vector<char> B2 = build_tree_from_terminals(terminals_from_P(P2));\n        consider(P2, B2);\n\n        return bestLocal;\n    }\n\n    Candidate solve() {\n        vector<pair<long double,long double>> params = {\n            {0.00L, 1.00L},\n            {0.35L, 1.00L},\n            {0.70L, 1.00L},\n            {1.10L, 1.00L},\n            {0.35L, 1.15L},\n        };\n\n        Candidate bestAns;\n        for (auto [alpha, gamma] : params) {\n            if (elapsed() > 1.85) break;\n            Candidate cand = solve_variant(alpha, gamma);\n            if (better(cand, bestAns, K)) bestAns = std::move(cand);\n        }\n\n        // Fallback, should rarely matter.\n        if (bestAns.covered < 0) {\n            vector<int> P(N, 0);\n            vector<char> B(M, 0);\n            bestAns = make_candidate(P, B);\n        }\n        return bestAns;\n    }\n\n    void output(const Candidate& ans) const {\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans.P[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << int(ans.B[i]);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.input();\n    solver.precompute();\n    Candidate ans = solver.solve();\n    solver.output(ans);\n    return 0;\n}","ahc021":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nusing Board = array<array<int, N>, N>;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    int E = 0;\n\n    long long score_like() const {\n        if ((int)ops.size() > 10000) return -(1LL << 60);\n        if (E == 0) return 100000LL - 5LL * (int)ops.size();\n        return 50000LL - 50LL * E;\n    }\n};\n\nint count_violations(const Board& a) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++E;\n            if (a[x][y] > a[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nBoard reflect_board(const Board& a) {\n    Board b{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            b[x][y] = a[x][x - y];\n        }\n    }\n    return b;\n}\n\nvector<Op> reflect_ops(vector<Op> ops) {\n    for (auto& op : ops) {\n        op.y1 = op.x1 - op.y1;\n        op.y2 = op.x2 - op.y2;\n    }\n    return ops;\n}\n\nbool better_candidate(const Candidate& a, const Candidate& b) {\n    if (a.score_like() != b.score_like()) return a.score_like() > b.score_like();\n    if (a.E != b.E) return a.E < b.E;\n    return a.ops.size() < b.ops.size();\n}\n\nstruct Builder {\n    Board a;\n    vector<Op> ops;\n\n    Builder(const Board& init) : a(init) {}\n\n    static bool reachable_down(int r, int c, int tr, int tc) {\n        // Can (r,c) reach (tr,tc) using only down-left (same c) / down-right (c+1)?\n        if (r > tr) return false;\n        if (c < 0 || c > r) return false;\n        return (c <= tc && tc <= c + (tr - r));\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        swap(a[x1][y1], a[x2][y2]);\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    pair<int,int> find_min_subtriangle(int x, int y) const {\n        int best_v = INT_MAX;\n        pair<int,int> best = {x, y};\n        for (int i = x; i < N; ++i) {\n            int l = y;\n            int r = y + (i - x);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] < best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    pair<int,int> find_max_uppertriangle(int x, int y) const {\n        int best_v = -1;\n        pair<int,int> best = {x, y};\n        for (int i = 0; i <= x; ++i) {\n            int l = max(0, y - (x - i));\n            int r = min(i, y);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] > best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_best_path_top(int tx, int ty, int sx, int sy) const {\n        // Move value from source (sx,sy) up to target (tx,ty).\n        // Among shortest paths, maximize sum of shifted-down values.\n        const int NEG = -1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                dp[i][j] = NEG;\n\n        dp[sx][sy] = 0;\n\n        for (int r = sx - 1; r >= tx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, sx, sy)) continue;\n                int best = NEG;\n                if (reachable_down(r + 1, c, sx, sy) && dp[r + 1][c] != NEG) {\n                    best = max(best, dp[r + 1][c]);\n                }\n                if (reachable_down(r + 1, c + 1, sx, sy) && dp[r + 1][c + 1] != NEG) {\n                    best = max(best, dp[r + 1][c + 1]);\n                }\n                if (best != NEG) dp[r][c] = a[r][c] + best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = tx, c = ty;\n        path.push_back({r, c});\n\n        while (!(r == sx && c == sy)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = NEG;\n\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, sx, sy)) return;\n                if (dp[nr][nc] == NEG) return;\n                if (nxt.first == -1 ||\n                    dp[nr][nc] > best ||\n                    (dp[nr][nc] == best && a[nr][nc] > a[nxt.first][nxt.second])) {\n                    best = dp[nr][nc];\n                    nxt = {nr, nc};\n                }\n            };\n\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back(nxt);\n        }\n\n        return path;\n    }\n\n    vector<pair<int,int>> build_best_path_bottom(int sx, int sy, int tx, int ty) const {\n        // Move value from source (sx,sy) down to target (tx,ty).\n        // Among shortest paths, minimize sum of shifted-up values.\n        const int INF = 1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                dp[i][j] = INF;\n\n        dp[tx][ty] = 0;\n\n        for (int r = tx - 1; r >= sx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, tx, ty)) continue;\n                int best = INF;\n                if (reachable_down(r + 1, c, tx, ty) && dp[r + 1][c] != INF) {\n                    best = min(best, a[r + 1][c] + dp[r + 1][c]);\n                }\n                if (reachable_down(r + 1, c + 1, tx, ty) && dp[r + 1][c + 1] != INF) {\n                    best = min(best, a[r + 1][c + 1] + dp[r + 1][c + 1]);\n                }\n                dp[r][c] = best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = sx, c = sy;\n        path.push_back({r, c});\n\n        while (!(r == tx && c == ty)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = INF;\n\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, tx, ty)) return;\n                if (dp[nr][nc] == INF) return;\n                int cand = a[nr][nc] + dp[nr][nc];\n                if (nxt.first == -1 ||\n                    cand < best ||\n                    (cand == best && a[nr][nc] < a[nxt.first][nxt.second])) {\n                    best = cand;\n                    nxt = {nr, nc};\n                }\n            };\n\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back(nxt);\n        }\n\n        return path;\n    }\n\n    Candidate solve_topdown() {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_min_subtriangle(x, y);\n                auto path = build_best_path_top(x, y, sx, sy);\n                for (int i = (int)path.size() - 1; i >= 1; --i) {\n                    auto [x1, y1] = path[i];\n                    auto [x2, y2] = path[i - 1];\n                    do_swap(x1, y1, x2, y2);\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n\n    Candidate solve_bottomup() {\n        for (int x = N - 1; x >= 0; --x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_max_uppertriangle(x, y);\n                auto path = build_best_path_bottom(sx, sy, x, y);\n                for (int i = 1; i < (int)path.size(); ++i) {\n                    auto [x1, y1] = path[i - 1];\n                    auto [x2, y2] = path[i];\n                    do_swap(x1, y1, x2, y2);\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board init{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n        }\n    }\n\n    vector<Candidate> cands;\n\n    // Baseline: do nothing (always valid).\n    cands.push_back(Candidate{{}, count_violations(init)});\n\n    // Top-down on original.\n    {\n        Builder b(init);\n        cands.push_back(b.solve_topdown());\n    }\n\n    // Top-down on reflected board.\n    {\n        Board rb = reflect_board(init);\n        Builder b(rb);\n        Candidate c = b.solve_topdown();\n        c.ops = reflect_ops(std::move(c.ops));\n        cands.push_back(std::move(c));\n    }\n\n    // Bottom-up on original.\n    {\n        Builder b(init);\n        cands.push_back(b.solve_bottomup());\n    }\n\n    // Bottom-up on reflected board.\n    {\n        Board rb = reflect_board(init);\n        Builder b(rb);\n        Candidate c = b.solve_bottomup();\n        c.ops = reflect_ops(std::move(c.ops));\n        cands.push_back(std::move(c));\n    }\n\n    Candidate best = cands[0];\n    for (size_t i = 1; i < cands.size(); ++i) {\n        if (better_candidate(cands[i], best)) best = std::move(cands[i]);\n    }\n\n    if ((int)best.ops.size() > 10000) {\n        // Safety fallback; should almost never happen.\n        best.ops.clear();\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (auto &op : best.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick() : n(0) {}\n    Fenwick(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int r) const { // [0, r)\n        int s = 0;\n        for (; r > 0; r -= r & -r) s += bit[r];\n        return s;\n    }\n    int total() const { return sumPrefix(n); }\n};\n\nstruct Strategy {\n    int hmode; // peel-order heuristic\n    int smode; // choose mode\n};\n\nstruct PeelInfo {\n    array<int, 81> pos;\n    vector<int> safe0;\n};\n\nclass Solver {\n    static constexpr int V = 81;\n    int D, N, M;\n    int root;\n    array<char, V> obstacle{};\n    array<vector<int>, V> adj;\n    array<int, V> dist0{};\n    vector<int> cells; // non-obstacle, non-root cells\n\n    Strategy best_strategy{0, 0};\n    array<int, V> label{};\n\n    int id(int i, int j) const { return i * D + j; }\n\n    void build_adj() {\n        for (int v = 0; v < V; ++v) adj[v].clear();\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int u = id(i, j);\n                if (obstacle[u]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir], nj = j + dj[dir];\n                    if (ni < 0 || ni >= D || nj < 0 || nj >= D) continue;\n                    int v = id(ni, nj);\n                    if (obstacle[v]) continue;\n                    adj[u].push_back(v);\n                }\n            }\n        }\n    }\n\n    void bfs_dist(const array<char, V>& active, array<int, V>& dist) const {\n        dist.fill(-1);\n        queue<int> q;\n        if (!active[root]) return;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (!active[v] || dist[v] != -1) continue;\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n\n    void dfs_art(\n        int u, int p,\n        const array<char, V>& active,\n        array<int, V>& ord,\n        array<int, V>& low,\n        array<char, V>& arti,\n        int& timer\n    ) const {\n        ord[u] = low[u] = timer++;\n        int child = 0;\n        for (int v : adj[u]) {\n            if (!active[v]) continue;\n            if (ord[v] == -1) {\n                ++child;\n                dfs_art(v, u, active, ord, low, arti, timer);\n                low[u] = min(low[u], low[v]);\n                if (p != -1 && low[v] >= ord[u]) arti[u] = 1;\n            } else if (v != p) {\n                low[u] = min(low[u], ord[v]);\n            }\n        }\n        if (p == -1 && child > 1) arti[u] = 1;\n    }\n\n    void compute_articulation(const array<char, V>& active, array<char, V>& arti) const {\n        arti.fill(0);\n        array<int, V> ord, low;\n        ord.fill(-1);\n        low.fill(-1);\n        int timer = 0;\n        if (active[root]) dfs_art(root, -1, active, ord, low, arti, timer);\n    }\n\n    array<int, 4> make_key(\n        int v,\n        const array<int, V>& dist,\n        const array<int, V>& deg,\n        int hmode\n    ) const {\n        // Bigger key => removed earlier in canonical peel\n        if (hmode == 0) {\n            // Dynamic distance first\n            return {dist[v], -deg[v], dist0[v], -v};\n        } else if (hmode == 1) {\n            // Static distance first\n            return {dist0[v], -deg[v], dist[v], -v};\n        } else {\n            // Mixed\n            return {2 * dist[v] + dist0[v], -deg[v], dist[v], -v};\n        }\n    }\n\n    PeelInfo peel_info(const array<char, V>& occupied, const Strategy& st) const {\n        PeelInfo info;\n        info.pos.fill(-1);\n        info.safe0.clear();\n\n        array<char, V> active{};\n        active.fill(0);\n        active[root] = 1;\n        int rem = 0;\n        for (int v : cells) {\n            if (!occupied[v]) {\n                active[v] = 1;\n                ++rem;\n            }\n        }\n\n        for (int step = 0; step < rem; ++step) {\n            array<int, V> dist;\n            bfs_dist(active, dist);\n\n            array<char, V> arti;\n            compute_articulation(active, arti);\n\n            array<int, V> deg{};\n            deg.fill(0);\n            for (int u = 0; u < V; ++u) {\n                if (!active[u]) continue;\n                for (int v : adj[u]) if (active[v]) ++deg[u];\n            }\n\n            vector<int> safe;\n            int best = -1;\n            array<int, 4> bestKey{};\n\n            for (int v : cells) {\n                if (!active[v]) continue;\n                if (dist[v] == -1) continue; // should not happen\n                if (arti[v]) continue;\n                safe.push_back(v);\n                auto key = make_key(v, dist, deg, st.hmode);\n                if (best == -1 || key > bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n\n            if (step == 0) info.safe0 = safe;\n\n            if (best == -1) {\n                // Fallback; theoretically unnecessary\n                for (int v : cells) {\n                    if (active[v] && dist[v] != -1) {\n                        best = v;\n                        break;\n                    }\n                }\n                if (step == 0 && info.safe0.empty() && best != -1) {\n                    info.safe0.push_back(best);\n                }\n            }\n\n            if (best == -1) break;\n            info.pos[best] = step;\n            active[best] = 0;\n        }\n\n        return info;\n    }\n\n    int choose_cell(const array<char, V>& occupied, const Fenwick& unseen, int t, const Strategy& st) const {\n        int m = unseen.total();\n        int r = unseen.sumPrefix(t); // current label rank among unseen\n\n        PeelInfo info = peel_info(occupied, st);\n        vector<int> safe = info.safe0;\n\n        if (safe.empty()) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) if (!occupied[v]) return v;\n            return cells.front();\n        }\n\n        if (st.smode == 0) {\n            // Quantile among currently legal choices\n            sort(safe.begin(), safe.end(), [&](int a, int b) {\n                if (info.pos[a] != info.pos[b]) return info.pos[a] > info.pos[b];\n                return a < b;\n            });\n            int idx = (int)((long long)r * (int)safe.size() / m);\n            if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n            return safe[idx];\n        } else {\n            // Closest to absolute target position in canonical peel\n            int target = m - 1 - r; // large => early output\n            int best = -1;\n            pair<int, int> bestPair{INT_MAX, INT_MAX};\n            for (int v : safe) {\n                int d = abs(info.pos[v] - target);\n                int tie = (target * 2 >= m - 1) ? -info.pos[v] : info.pos[v];\n                pair<int, int> cur{d, tie};\n                if (best == -1 || cur < bestPair) {\n                    best = v;\n                    bestPair = cur;\n                }\n            }\n            return best;\n        }\n    }\n\n    int best_reachable_smallest(const array<char, V>& occ, const array<int, V>& lbl) const {\n        array<char, V> vis{};\n        vis.fill(0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n\n        int best = -1;\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (occ[v]) {\n                    if (best == -1 || lbl[v] < lbl[best]) best = v;\n                } else {\n                    if (!vis[v]) {\n                        vis[v] = 1;\n                        q.push(v);\n                    }\n                }\n            }\n        }\n\n        if (best == -1) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) {\n                if (occ[v] && (best == -1 || lbl[v] < lbl[best])) best = v;\n            }\n        }\n        return best;\n    }\n\n    long long simulate(const Strategy& st, const vector<int>& perm) const {\n        array<char, V> occ{};\n        occ.fill(0);\n        array<int, V> lbl;\n        lbl.fill(-1);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int x : perm) {\n            int c = choose_cell(occ, unseen, x, st);\n            occ[c] = 1;\n            lbl[c] = x;\n            unseen.add(x, -1);\n        }\n\n        array<char, V> curOcc = occ;\n        vector<int> out;\n        out.reserve(M);\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, lbl);\n            out.push_back(lbl[c]);\n            curOcc[c] = 0;\n        }\n\n        long long inv = 0;\n        for (int i = 0; i < M; ++i) {\n            for (int j = i + 1; j < M; ++j) {\n                if (out[i] > out[j]) ++inv;\n            }\n        }\n        return inv;\n    }\n\n    void train_best_strategy() {\n        vector<Strategy> cand = {\n            {0, 0}, {0, 1},\n            {1, 0}, {1, 1},\n            {2, 0}, {2, 1}\n        };\n\n        uint64_t seed = 1469598103934665603ULL;\n        seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n        for (int v = 0; v < V; ++v) {\n            if (obstacle[v]) {\n                seed ^= (uint64_t)(v + 1);\n                seed *= 1099511628211ULL;\n            }\n        }\n        mt19937_64 rng(seed);\n\n        const int TRAIN_ITERS = 4;\n        vector<vector<int>> perms(TRAIN_ITERS, vector<int>(M));\n        for (int it = 0; it < TRAIN_ITERS; ++it) {\n            iota(perms[it].begin(), perms[it].end(), 0);\n            shuffle(perms[it].begin(), perms[it].end(), rng);\n        }\n\n        long long bestScore = (1LL << 62);\n        for (const auto& st : cand) {\n            long long sumInv = 0;\n            for (int it = 0; it < TRAIN_ITERS; ++it) {\n                sumInv += simulate(st, perms[it]);\n            }\n            if (sumInv < bestScore) {\n                bestScore = sumInv;\n                best_strategy = st;\n            }\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> D >> N;\n        root = id(0, (D - 1) / 2);\n\n        obstacle.fill(0);\n        label.fill(-1);\n\n        for (int k = 0; k < N; ++k) {\n            int i, j;\n            cin >> i >> j;\n            obstacle[id(i, j)] = 1;\n        }\n\n        build_adj();\n\n        cells.clear();\n        for (int v = 0; v < V; ++v) {\n            if (!obstacle[v] && v != root) cells.push_back(v);\n        }\n        M = (int)cells.size();\n\n        // Original distances\n        array<char, V> active{};\n        active.fill(0);\n        for (int v = 0; v < V; ++v) if (!obstacle[v]) active[v] = 1;\n        bfs_dist(active, dist0);\n\n        train_best_strategy();\n\n        array<char, V> occupied{};\n        occupied.fill(0);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int d = 0; d < M; ++d) {\n            int t;\n            cin >> t;\n\n            int c = choose_cell(occupied, unseen, t, best_strategy);\n            occupied[c] = 1;\n            label[c] = t;\n            unseen.add(t, -1);\n\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            cout.flush();\n        }\n\n        array<char, V> curOcc = occupied;\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, label);\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            curOcc[c] = 0;\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXV = 2500;\nstatic constexpr int MAXC = 101;\n\nint n, m;\n\nbool origAdj[MAXC][MAXC];\nint distColor[MAXC];\nint degColor[MAXC];\n\narray<array<int, 4>, MAXV> neighbors_idx;\narray<int, MAXV> neighbors_cnt;\narray<int, MAXV> boundary_sides;\n\nint vis_stamp[MAXV];\nint cur_stamp = 1;\n\nstruct State {\n    array<int, MAXV> g{};\n    array<int, MAXC> cnt{};\n    array<array<int, MAXC>, MAXC> edge{};\n    long long distSum = 0;\n};\n\ninline void add_edge(array<array<int, MAXC>, MAXC>& edge, int a, int b, int delta) {\n    if (a == b) return;\n    edge[a][b] += delta;\n    edge[b][a] += delta;\n}\n\nState build_state(const vector<int>& init) {\n    State st;\n    for (auto& row : st.edge) row.fill(0);\n    st.cnt.fill(0);\n    st.distSum = 0;\n\n    const int V = n * n;\n    for (int idx = 0; idx < V; ++idx) {\n        st.g[idx] = init[idx];\n        st.cnt[st.g[idx]]++;\n        st.distSum += distColor[st.g[idx]];\n    }\n\n    for (int idx = 0; idx < V; ++idx) {\n        int c = st.g[idx];\n        int i = idx / n, j = idx % n;\n\n        if (i == 0) add_edge(st.edge, c, 0, 1);\n        if (i == n - 1) add_edge(st.edge, c, 0, 1);\n        if (j == 0) add_edge(st.edge, c, 0, 1);\n        if (j == n - 1) add_edge(st.edge, c, 0, 1);\n\n        if (i + 1 < n) add_edge(st.edge, c, st.g[idx + n], 1);\n        if (j + 1 < n) add_edge(st.edge, c, st.g[idx + 1], 1);\n    }\n\n    return st;\n}\n\nbool connected_after_remove(const State& st, int color, int remIdx, int need, int startIdx) {\n    ++cur_stamp;\n    if (cur_stamp == INT_MAX) {\n        memset(vis_stamp, 0, sizeof(vis_stamp));\n        cur_stamp = 1;\n    }\n\n    static int q[MAXV];\n    int ql = 0, qr = 0;\n    q[qr++] = startIdx;\n    vis_stamp[startIdx] = cur_stamp;\n    int seen = 1;\n\n    while (ql < qr) {\n        int v = q[ql++];\n        int deg = neighbors_cnt[v];\n        for (int k = 0; k < deg; ++k) {\n            int to = neighbors_idx[v][k];\n            if (to == remIdx) continue;\n            if (st.g[to] != color) continue;\n            if (vis_stamp[to] == cur_stamp) continue;\n            vis_stamp[to] = cur_stamp;\n            q[qr++] = to;\n            ++seen;\n            if (seen == need) return true;\n        }\n    }\n    return seen == need;\n}\n\nbool try_move(State& st, int idx, int t) {\n    int c = st.g[idx];\n    if (c == 0 || c == t) return false;\n    if (st.cnt[c] <= 1) return false; // never delete a color entirely\n\n    int sameNbr = 0;\n    int startIdx = -1;\n    bool targetConnected = false;\n\n    if (t == 0 && boundary_sides[idx] > 0) targetConnected = true;\n\n    int pa[10], pb[10], pd[10];\n    int pnum = 0;\n\n    auto add_change = [&](int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < pnum; ++i) {\n            if (pa[i] == a && pb[i] == b) {\n                pd[i] += d;\n                return;\n            }\n        }\n        pa[pnum] = a;\n        pb[pnum] = b;\n        pd[pnum] = d;\n        ++pnum;\n    };\n\n    int deg = neighbors_cnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        int to = neighbors_idx[idx][k];\n        int d = st.g[to];\n\n        if (d == c) {\n            ++sameNbr;\n            startIdx = to;\n        }\n        if (d == t) targetConnected = true;\n        if (t == 0 && d == 0) targetConnected = true;\n\n        if (c != d) add_change(c, d, -1);\n        if (t != d) add_change(t, d, +1);\n    }\n\n    if (boundary_sides[idx] > 0) {\n        add_change(c, 0, -boundary_sides[idx]);\n        add_change(t, 0, +boundary_sides[idx]);\n    }\n\n    if (!targetConnected) return false;\n    if (sameNbr == 0) return false; // connected source color cannot have 0 same-color neighbors unless size 1\n\n    // Adjacency constraints: only changed pairs need to be checked.\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        int newCnt = st.edge[a][b] + pd[i];\n        if (newCnt < 0) return false;\n        bool newAdj = (newCnt > 0);\n        if (newAdj != origAdj[a][b]) return false;\n    }\n\n    // Source connectivity.\n    if (sameNbr >= 2) {\n        if (!connected_after_remove(st, c, idx, st.cnt[c] - 1, startIdx)) return false;\n    }\n    // sameNbr == 1 is always safe for connectivity of c.\n\n    // Apply.\n    st.g[idx] = t;\n    st.cnt[c]--;\n    st.cnt[t]++;\n    st.distSum += (long long)distColor[t] - distColor[c];\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        st.edge[a][b] += pd[i];\n        st.edge[b][a] += pd[i];\n    }\n\n    return true;\n}\n\narray<int, MAXC> make_key(const State& st, mt19937& rng, const vector<vector<int>>& depthGroups) {\n    array<int, MAXC> key{};\n    key.fill(0);\n    key[0] = 0;\n\n    for (int d = 1; d < (int)depthGroups.size(); ++d) {\n        vector<int> v = depthGroups[d];\n        shuffle(v.begin(), v.end(), rng);\n        stable_sort(v.begin(), v.end(), [&](int a, int b) {\n            if (degColor[a] != degColor[b]) return degColor[a] > degColor[b];\n            if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n            return false;\n        });\n        for (int i = 0; i < (int)v.size(); ++i) {\n            key[v[i]] = d * 1000 + (i + 1);\n        }\n    }\n\n    return key;\n}\n\nvoid optimize(State& st,\n              const array<int, MAXC>& key,\n              mt19937& rng,\n              chrono::steady_clock::time_point deadline) {\n    const int V = n * n;\n    vector<int> ord(V);\n    iota(ord.begin(), ord.end(), 0);\n\n    while (chrono::steady_clock::now() < deadline) {\n        shuffle(ord.begin(), ord.end(), rng);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return key[st.g[a]] > key[st.g[b]];\n        });\n\n        bool moved = false;\n\n        for (int it = 0; it < V; ++it) {\n            if ((it & 255) == 0 && chrono::steady_clock::now() >= deadline) return;\n\n            int idx = ord[it];\n            int c = st.g[idx];\n            if (c == 0) continue;\n\n            int cand[5];\n            int ccnt = 0;\n\n            auto add_cand = [&](int x) {\n                if (x == c) return;\n                if (key[x] >= key[c]) return;\n                for (int i = 0; i < ccnt; ++i) {\n                    if (cand[i] == x) return;\n                }\n                cand[ccnt++] = x;\n            };\n\n            if (boundary_sides[idx] > 0) add_cand(0);\n            int deg = neighbors_cnt[idx];\n            for (int k = 0; k < deg; ++k) {\n                add_cand(st.g[neighbors_idx[idx][k]]);\n            }\n\n            sort(cand, cand + ccnt, [&](int a, int b) {\n                return key[a] < key[b];\n            });\n\n            for (int i = 0; i < ccnt; ++i) {\n                if (try_move(st, idx, cand[i])) {\n                    moved = true;\n                    break;\n                }\n            }\n        }\n\n        if (!moved) break;\n    }\n}\n\nbool better(const State& a, const State& b) {\n    if (a.cnt[0] != b.cnt[0]) return a.cnt[0] > b.cnt[0];\n    return a.distSum < b.distSum;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n >> m;\n    vector<int> init(n * n);\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            cin >> init[i * n + j];\n        }\n    }\n\n    // Precompute neighborhood info.\n    for (int idx = 0; idx < n * n; ++idx) {\n        int i = idx / n, j = idx % n;\n        int c = 0;\n        if (i > 0) neighbors_idx[idx][c++] = idx - n;\n        if (i + 1 < n) neighbors_idx[idx][c++] = idx + n;\n        if (j > 0) neighbors_idx[idx][c++] = idx - 1;\n        if (j + 1 < n) neighbors_idx[idx][c++] = idx + 1;\n        neighbors_cnt[idx] = c;\n        boundary_sides[idx] = (i == 0) + (i == n - 1) + (j == 0) + (j == n - 1);\n    }\n\n    // Original adjacency graph.\n    memset(origAdj, 0, sizeof(origAdj));\n    for (int idx = 0; idx < n * n; ++idx) {\n        int c = init[idx];\n        int i = idx / n, j = idx % n;\n        if (i == 0 || i == n - 1 || j == 0 || j == n - 1) {\n            origAdj[c][0] = origAdj[0][c] = true;\n        }\n        if (i + 1 < n) {\n            int d = init[idx + n];\n            if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n        }\n        if (j + 1 < n) {\n            int d = init[idx + 1];\n            if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n        }\n    }\n\n    // Distances from outside in the original adjacency graph.\n    const int INF = 1e9;\n    for (int i = 0; i <= m; ++i) distColor[i] = INF;\n    queue<int> q;\n    distColor[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (int to = 0; to <= m; ++to) {\n            if (!origAdj[v][to]) continue;\n            if (distColor[to] != INF) continue;\n            distColor[to] = distColor[v] + 1;\n            q.push(to);\n        }\n    }\n\n    for (int i = 0; i <= m; ++i) {\n        int dg = 0;\n        for (int j = 0; j <= m; ++j) if (origAdj[i][j]) ++dg;\n        degColor[i] = dg;\n    }\n\n    int maxDepth = 0;\n    for (int c = 1; c <= m; ++c) maxDepth = max(maxDepth, distColor[c]);\n    vector<vector<int>> depthGroups(maxDepth + 1);\n    for (int c = 1; c <= m; ++c) depthGroups[distColor[c]].push_back(c);\n\n    State original = build_state(init);\n    State best = original;\n    State cur = original;\n\n    mt19937 rng(123456789);\n    auto start = chrono::steady_clock::now();\n    auto deadline = start + chrono::milliseconds(1850);\n\n    int round = 0;\n    while (chrono::steady_clock::now() < deadline) {\n        if (round > 0 && round % 8 == 0) {\n            // Diversification: restart from original.\n            State cand = original;\n            auto key = make_key(cand, rng, depthGroups);\n            optimize(cand, key, rng, deadline);\n            if (better(cand, best) || (cand.cnt[0] == best.cnt[0] && cand.distSum == best.distSum)) {\n                best = cand;\n                cur = cand;\n            } else {\n                cur = best;\n            }\n        } else {\n            // Intensification: continue from current best branch.\n            auto key = make_key(cur, rng, depthGroups);\n            optimize(cur, key, rng, deadline);\n            if (better(cur, best) || (cur.cnt[0] == best.cnt[0] && cur.distSum == best.distSum)) {\n                best = cur;\n            } else {\n                cur = best;\n            }\n        }\n        ++round;\n    }\n\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << best.g[i * n + j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n\n    vector<int> cost_ins;                    // upper bound for binary insertion sort cost\n    vector<vector<signed char>> itemMemo;    // item pair comparison cache\n    vector<vector<signed char>> blockMemo;   // block comparison cache\n\n    vector<vector<int>> blocks;\n    vector<vector<int>> bins;\n\n    vector<int> order_est;   // estimated descending order (heavy -> light)\n    vector<int> rank_pos;    // estimated rank position for each item\n    vector<double> pweight;  // pseudo weight from estimated rank\n    vector<double> est_load; // estimated bin loads\n    vector<double> harm;     // harmonic numbers\n\n    int M = 1;\n    int baseSize = 1;\n    int remBlocks = 0;\n    int iterBound = 0;\n    int reserve_balance = 0;\n\n    static signed char enc(char c) {\n        if (c == '>') return 1;\n        if (c == '<') return -1;\n        return 2;\n    }\n    static char dec(signed char v) {\n        if (v == 1) return '>';\n        if (v == -1) return '<';\n        return '=';\n    }\n    static char rev(char c) {\n        if (c == '>') return '<';\n        if (c == '<') return '>';\n        return '=';\n    }\n\n    int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 0, y = 1;\n        while (y < x) y <<= 1, ++p;\n        return p;\n    }\n\n    char ask_sets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) {\n            // Should never happen.\n            exit(0);\n        }\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        ++used;\n        return s[0];\n    }\n\n    char cmp_item(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = itemMemo[a][b];\n        if (m != 0) return dec(m);\n        char s = ask_sets(vector<int>{a}, vector<int>{b});\n        itemMemo[a][b] = enc(s);\n        itemMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    char cmp_block(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = blockMemo[a][b];\n        if (m != 0) return dec(m);\n\n        vector<int> L, R;\n        L.reserve(baseSize);\n        R.reserve(baseSize);\n        for (int i = 0; i < baseSize; ++i) L.push_back(blocks[a][i]);\n        for (int i = 0; i < baseSize; ++i) R.push_back(blocks[b][i]);\n\n        char s = ask_sets(L, R);\n        blockMemo[a][b] = enc(s);\n        blockMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    void precompute_costs() {\n        cost_ins.assign(N + 1, 0);\n        for (int n = 1; n <= N; ++n) {\n            cost_ins[n] = cost_ins[n - 1] + ceil_log2_int(n);\n        }\n\n        harm.assign(N + 1, 0.0);\n        for (int i = 1; i <= N; ++i) harm[i] = harm[i - 1] + 1.0 / i;\n    }\n\n    int scheme_cost(int m) {\n        int base = N / m;\n        int rem = N % m;\n        long long c = 1LL * rem * cost_ins[base + 1]\n                    + 1LL * (m - rem) * cost_ins[base]\n                    + cost_ins[m];\n        return (int)c;\n    }\n\n    void choose_scheme() {\n        iterBound = 2 * (D - 1) + 6 + 2 * ceil_log2_int(N);\n        reserve_balance = min(Q, 2 * iterBound);\n\n        double bestScore = -1e100;\n        int bestM = 1;\n\n        for (int m = 1; m <= N; ++m) {\n            int c = scheme_cost(m);\n            if (c > Q) continue;\n            int extra = max(0, Q - c - reserve_balance);\n            double place_cnt = 0.0;\n            if (D > 1) {\n                place_cnt = min<double>(N - D, extra / double(D - 1));\n            }\n            double score = m + 0.8 * place_cnt;\n            if (score > bestScore + 1e-12 || (abs(score - bestScore) <= 1e-12 && m > bestM)) {\n                bestScore = score;\n                bestM = m;\n            }\n        }\n\n        M = bestM;\n        baseSize = N / M;\n        remBlocks = N % M;\n    }\n\n    vector<int> sort_items_by_weight(const vector<int>& arr) {\n        vector<int> res;\n        res.reserve(arr.size());\n        for (int x : arr) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_item(x, res[mid]); // '>' => x heavier\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, x);\n        }\n        return res;\n    }\n\n    vector<int> sort_block_ids(const vector<int>& ids) {\n        vector<int> res;\n        res.reserve(ids.size());\n        for (int id : ids) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_block(id, res[mid]); // '>' => id heavier\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, id);\n        }\n        return res;\n    }\n\n    void build_estimated_order() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n\n        blocks.clear();\n        int cur = 0;\n        for (int i = 0; i < M; ++i) {\n            int sz = baseSize + (i < remBlocks ? 1 : 0);\n            vector<int> blk;\n            blk.reserve(sz);\n            for (int j = 0; j < sz; ++j) blk.push_back(items[cur++]);\n            blocks.push_back(sort_items_by_weight(blk));\n        }\n\n        blockMemo.assign(M, vector<signed char>(M, 0));\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        ids = sort_block_ids(ids);\n\n        order_est.clear();\n        order_est.reserve(N);\n        for (int id : ids) {\n            for (int x : blocks[id]) order_est.push_back(x);\n        }\n\n        rank_pos.assign(N, 0);\n        pweight.assign(N, 0.0);\n        for (int pos = 0; pos < N; ++pos) {\n            int x = order_est[pos];\n            rank_pos[x] = pos;\n            pweight[x] = harm[N] - harm[pos]; // expected weight of pos-th largest (up to scale)\n        }\n    }\n\n    int actual_lightest_bin_simple() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            char s = ask_sets(bins[i], bins[best]);\n            if (s == '<') best = i;\n        }\n        return best;\n    }\n\n    int pseudo_lightest_bin() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            if (est_load[i] < est_load[best] - 1e-12) best = i;\n            else if (abs(est_load[i] - est_load[best]) <= 1e-12) {\n                if (bins[i].size() < bins[best].size()) best = i;\n                else if (bins[i].size() == bins[best].size() && i < best) best = i;\n            }\n        }\n        return best;\n    }\n\n    void insert_sorted_bin(int b, int item) {\n        auto &v = bins[b];\n        int rk = rank_pos[item];\n        auto it = lower_bound(v.begin(), v.end(), rk,\n                              [&](int lhs_item, int rhs_rank) {\n                                  return rank_pos[lhs_item] < rhs_rank;\n                              });\n        v.insert(it, item);\n    }\n\n    void assign_initial() {\n        bins.assign(D, {});\n        est_load.assign(D, 0.0);\n\n        for (int i = 0; i < N; ++i) {\n            int x = order_est[i];\n            int b;\n            if (i < D) {\n                b = i; // ensure all nonempty\n            } else if (used + (D - 1) + reserve_balance <= Q) {\n                b = actual_lightest_bin_simple();\n            } else {\n                b = pseudo_lightest_bin();\n            }\n            bins[b].push_back(x); // order_est is descending, so push_back keeps bin sorted\n            est_load[b] += pweight[x];\n        }\n    }\n\n    void pseudo_improve() {\n        for (int iter = 0; iter < 2000; ++iter) {\n            int h = 0, l = 0;\n            for (int i = 1; i < D; ++i) {\n                if (est_load[i] > est_load[h]) h = i;\n                if (est_load[i] < est_load[l]) l = i;\n            }\n            if (h == l) break;\n\n            double lh = est_load[h], ll = est_load[l];\n            double bestDelta = -1e-12;\n            int bestType = 0; // 1 move, 2 swap\n            int bestI = -1, bestJ = -1;\n\n            if ((int)bins[h].size() > 1) {\n                for (int i = 0; i < (int)bins[h].size(); ++i) {\n                    int x = bins[h][i];\n                    double w = pweight[x];\n                    double nh = lh - w;\n                    double nl = ll + w;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 1;\n                        bestI = i;\n                    }\n                }\n            }\n\n            for (int i = 0; i < (int)bins[h].size(); ++i) {\n                int x = bins[h][i];\n                double wx = pweight[x];\n                for (int j = 0; j < (int)bins[l].size(); ++j) {\n                    int y = bins[l][j];\n                    double wy = pweight[y];\n                    double nh = lh - wx + wy;\n                    double nl = ll - wy + wx;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 2;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestType == 0) break;\n\n            if (bestType == 1) {\n                int x = bins[h][bestI];\n                bins[h].erase(bins[h].begin() + bestI);\n                insert_sorted_bin(l, x);\n                est_load[h] -= pweight[x];\n                est_load[l] += pweight[x];\n            } else {\n                int x = bins[h][bestI];\n                int y = bins[l][bestJ];\n                bins[h].erase(bins[h].begin() + bestI);\n                bins[l].erase(bins[l].begin() + bestJ);\n                insert_sorted_bin(h, y);\n                insert_sorted_bin(l, x);\n                est_load[h] += pweight[y] - pweight[x];\n                est_load[l] += pweight[x] - pweight[y];\n            }\n        }\n    }\n\n    pair<int, int> actual_extremes() {\n        vector<vector<signed char>> memo(D, vector<signed char>(D, 0));\n        auto cmpBin = [&](int a, int b) -> char {\n            if (a == b) return '=';\n            signed char &m = memo[a][b];\n            if (m != 0) return dec(m);\n            char s = ask_sets(bins[a], bins[b]);\n            memo[a][b] = enc(s);\n            memo[b][a] = enc(rev(s));\n            return s;\n        };\n\n        int hi = 0, lo = 0;\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, hi) == '>') hi = i;\n        }\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, lo) == '<') lo = i;\n        }\n        return {hi, lo};\n    }\n\n    int select_move_candidate(int H, int L) {\n        int m = (int)bins[H].size();\n        if (m <= 1) return -1;\n\n        vector<signed char> memo(m, 0);\n        auto test = [&](int idx) -> char {\n            if (memo[idx] != 0) return dec(memo[idx]);\n            vector<int> left, right;\n            left.reserve(m - 1);\n            right.reserve(bins[L].size() + 1);\n            for (int i = 0; i < m; ++i) if (i != idx) left.push_back(bins[H][i]);\n            for (int x : bins[L]) right.push_back(x);\n            right.push_back(bins[H][idx]);\n            char s = ask_sets(left, right);\n            memo[idx] = enc(s);\n            return s;\n        };\n\n        char s0 = test(0);\n        if (s0 == '>' || s0 == '=') return 0;\n\n        char sl = test(m - 1);\n        if (sl == '=') return m - 1;\n        if (sl == '<') return -1; // even moving the lightest item overcompensates\n\n        int lo = 0, hi = m - 1; // test(lo) == '<', test(hi) == '>'\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '<') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double v1 = fabs(diff - 2.0 * pweight[bins[H][lo]]);\n        double v2 = fabs(diff - 2.0 * pweight[bins[H][hi]]);\n        return (v2 < v1 ? hi : lo);\n    }\n\n    int select_swap_candidate(int H, int L) {\n        int xidx = (int)bins[H].size() - 1; // lightest item in heavy bin\n        int x = bins[H][xidx];\n        int rkx = rank_pos[x];\n\n        int n = (int)bins[L].size();\n        int first = 0;\n        while (first < n && rank_pos[bins[L][first]] < rkx) ++first; // first estimated-lighter-than-x\n        if (first == n) return -1;\n\n        vector<signed char> memo(n, 0);\n        auto test = [&](int yidx) -> char {\n            if (memo[yidx] != 0) return dec(memo[yidx]);\n            vector<int> left, right;\n            left.reserve(bins[H].size());\n            right.reserve(bins[L].size());\n            for (int i = 0; i < (int)bins[H].size(); ++i) {\n                if (i != xidx) left.push_back(bins[H][i]);\n            }\n            left.push_back(bins[L][yidx]);\n\n            for (int i = 0; i < (int)bins[L].size(); ++i) {\n                if (i != yidx) right.push_back(bins[L][i]);\n            }\n            right.push_back(x);\n\n            char s = ask_sets(left, right);\n            memo[yidx] = enc(s);\n            return s;\n        };\n\n        char sf = test(first);\n        if (sf == '=') return first;\n        if (sf == '<') return -1; // even the smallest transfer overcompensates\n\n        char sl = test(n - 1);\n        if (sl == '=') return n - 1;\n        if (sl == '>') return n - 1; // even the largest transfer is still not enough\n\n        int lo = first, hi = n - 1; // test(lo) == '>', test(hi) == '<'\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '>') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double wx = pweight[x];\n        double d1 = fabs(diff - 2.0 * (wx - pweight[bins[L][lo]]));\n        double d2 = fabs(diff - 2.0 * (wx - pweight[bins[L][hi]]));\n        return (d2 < d1 ? hi : lo);\n    }\n\n    void apply_move(int H, int L, int idx) {\n        int x = bins[H][idx];\n        bins[H].erase(bins[H].begin() + idx);\n        insert_sorted_bin(L, x);\n        est_load[H] -= pweight[x];\n        est_load[L] += pweight[x];\n    }\n\n    void apply_swap(int H, int L, int yidx) {\n        int xidx = (int)bins[H].size() - 1;\n        int x = bins[H][xidx];\n        int y = bins[L][yidx];\n\n        bins[H].erase(bins[H].begin() + xidx);\n        bins[L].erase(bins[L].begin() + yidx);\n        insert_sorted_bin(H, y);\n        insert_sorted_bin(L, x);\n\n        est_load[H] += pweight[y] - pweight[x];\n        est_load[L] += pweight[x] - pweight[y];\n    }\n\n    void actual_improve() {\n        while (used + iterBound <= Q) {\n            auto [H, L] = actual_extremes();\n            if (H == L) break;\n\n            bool changed = false;\n\n            if ((int)bins[H].size() > 1) {\n                int idx = select_move_candidate(H, L);\n                if (idx != -1) {\n                    apply_move(H, L, idx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) {\n                int yidx = select_swap_candidate(H, L);\n                if (yidx != -1) {\n                    apply_swap(H, L, yidx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void fill_dummy_queries() {\n        while (used < Q) {\n            ask_sets(vector<int>{0}, vector<int>{1});\n        }\n    }\n\n    void output_answer() {\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b]) ans[x] = b;\n        }\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        itemMemo.assign(N, vector<signed char>(N, 0));\n\n        precompute_costs();\n        choose_scheme();\n        build_estimated_order();\n        assign_initial();\n        pseudo_improve();\n        actual_improve();\n        fill_dummy_queries();\n        output_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAX_N = 200;\nstatic constexpr int MAX_M = 10;\nstatic constexpr int INF_INT = 1e9;\n\nint gN, gM;\n\nstruct State {\n    int cur;                    // next box to carry out\n    int h[MAX_M];               // heights\n    int a[MAX_M][MAX_N];        // bottom -> top\n};\n\nstruct Params {\n    int depth;          // lookahead depth in expensive moves\n    int branchLimit;    // pruning width for deeper levels\n    int heuristicMode;  // 0/1/2\n    bool reverseTie;    // diversify tie-breaks\n};\n\nstruct Result {\n    int energy = INF_INT;\n    vector<pair<int,int>> ops;\n};\n\nstruct Child {\n    int t;          // destination stack\n    int moveCost;   // len + 1\n    int hval;       // heuristic after move + free pops\n    int nextCur;    // progressed cur after free pops\n    State st;       // resulting state\n};\n\ninline void pop_all(State& st, vector<pair<int,int>>* ops = nullptr) {\n    while (st.cur <= gN) {\n        int s = -1;\n        for (int i = 0; i < gM; ++i) {\n            if (st.h[i] > 0 && st.a[i][st.h[i] - 1] == st.cur) {\n                s = i;\n                break;\n            }\n        }\n        if (s == -1) break;\n        if (ops) ops->push_back({st.cur, 0});\n        --st.h[s];\n        ++st.cur;\n    }\n}\n\ninline void find_box(const State& st, int v, int& s, int& idx) {\n    for (int i = 0; i < gM; ++i) {\n        for (int j = 0; j < st.h[i]; ++j) {\n            if (st.a[i][j] == v) {\n                s = i;\n                idx = j;\n                return;\n            }\n        }\n    }\n    s = -1;\n    idx = -1;\n}\n\ninline int apply_move(State& st, int s, int idx, int t) {\n    // Move all boxes above box at (s, idx) onto stack t.\n    int start = idx + 1;\n    int len = st.h[s] - start;\n    for (int i = start; i < st.h[s]; ++i) {\n        st.a[t][st.h[t]++] = st.a[s][i];\n    }\n    st.h[s] = start;\n    return len;\n}\n\ninline int heuristic(const State& st, int mode) {\n    int bad = 0;\n    int badStacks = 0;\n    int aboveMin = 0;\n\n    for (int i = 0; i < gM; ++i) {\n        int h = st.h[i];\n        if (h == 0) continue;\n\n        int mn = gN + 1;\n        int good = 0;\n        int minPos = -1;\n\n        for (int j = 0; j < h; ++j) {\n            int x = st.a[i][j];\n            if (x < mn) {\n                mn = x;\n                ++good;\n                minPos = j;\n            }\n        }\n\n        int b = h - good;\n        bad += b;\n        if (b > 0) ++badStacks;\n        aboveMin += (h - 1 - minPos);\n    }\n\n    if (mode == 0) {\n        return bad + badStacks;\n    } else if (mode == 1) {\n        return bad * 2 + badStacks;\n    } else {\n        return bad + badStacks + aboveMin;\n    }\n}\n\ninline bool better_child_order(const Child& A, const Child& B, bool reverseTie) {\n    if (A.hval != B.hval) return A.hval < B.hval;\n    if (A.nextCur != B.nextCur) return A.nextCur > B.nextCur;\n    return reverseTie ? (A.t > B.t) : (A.t < B.t);\n}\n\nint search_cost(const State& st, int depth, const Params& p) {\n    if (st.cur > gN) return 0;\n\n    int s, idx;\n    find_box(st, st.cur, s, idx);\n\n    // Safety: if free pops are still possible, do them.\n    if (idx == st.h[s] - 1) {\n        State nxt = st;\n        pop_all(nxt, nullptr);\n        return search_cost(nxt, depth, p);\n    }\n\n    if (depth == 0) {\n        return heuristic(st, p.heuristicMode);\n    }\n\n    Child ch[MAX_M - 1];\n    int cnt = 0;\n\n    for (int t = 0; t < gM; ++t) {\n        if (t == s) continue;\n        ch[cnt].t = t;\n        ch[cnt].st = st;\n        int len = apply_move(ch[cnt].st, s, idx, t);\n        ch[cnt].moveCost = len + 1;\n        pop_all(ch[cnt].st, nullptr);\n        ch[cnt].hval = heuristic(ch[cnt].st, p.heuristicMode);\n        ch[cnt].nextCur = ch[cnt].st.cur;\n        ++cnt;\n    }\n\n    array<int, MAX_M - 1> ord{};\n    iota(ord.begin(), ord.begin() + cnt, 0);\n    sort(ord.begin(), ord.begin() + cnt, [&](int i, int j) {\n        return better_child_order(ch[i], ch[j], p.reverseTie);\n    });\n\n    int limit = cnt;\n    if (depth >= 3) limit = min(limit, p.branchLimit);\n\n    int best = INF_INT;\n    for (int k = 0; k < limit; ++k) {\n        const Child& c = ch[ord[k]];\n        int cand = c.moveCost + search_cost(c.st, depth - 1, p);\n        if (cand < best) best = cand;\n    }\n    return best;\n}\n\nResult simulate_strategy(const State& init, const Params& p) {\n    State st = init;\n    Result res;\n    res.energy = 0;\n    res.ops.clear();\n\n    pop_all(st, &res.ops);\n\n    while (st.cur <= gN) {\n        int s, idx;\n        find_box(st, st.cur, s, idx);\n\n        if (idx == st.h[s] - 1) {\n            pop_all(st, &res.ops);\n            continue;\n        }\n\n        Child ch[MAX_M - 1];\n        int cnt = 0;\n        for (int t = 0; t < gM; ++t) {\n            if (t == s) continue;\n            ch[cnt].t = t;\n            ch[cnt].st = st;\n            int len = apply_move(ch[cnt].st, s, idx, t);\n            ch[cnt].moveCost = len + 1;\n            pop_all(ch[cnt].st, nullptr);\n            ch[cnt].hval = heuristic(ch[cnt].st, p.heuristicMode);\n            ch[cnt].nextCur = ch[cnt].st.cur;\n            ++cnt;\n        }\n\n        int bestIdx = -1;\n        int bestVal = INF_INT;\n\n        for (int i = 0; i < cnt; ++i) {\n            int val = ch[i].moveCost + search_cost(ch[i].st, p.depth - 1, p);\n            if (bestIdx == -1 || val < bestVal) {\n                bestVal = val;\n                bestIdx = i;\n            } else if (val == bestVal) {\n                const Child& A = ch[i];\n                const Child& B = ch[bestIdx];\n                if (better_child_order(A, B, p.reverseTie)) {\n                    bestIdx = i;\n                }\n            }\n        }\n\n        int movedBox = st.a[s][idx + 1];\n        int dst = ch[bestIdx].t;\n\n        res.ops.push_back({movedBox, dst + 1});\n        res.energy += ch[bestIdx].moveCost;\n\n        apply_move(st, s, idx, dst);\n        pop_all(st, &res.ops);\n    }\n\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> gN >> gM;\n\n    State init{};\n    init.cur = 1;\n    int each = gN / gM;\n    for (int i = 0; i < gM; ++i) {\n        init.h[i] = each;\n        for (int j = 0; j < each; ++j) {\n            cin >> init.a[i][j];\n        }\n    }\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\n    vector<Params> paramsList = {\n        {4, 4, 0, false},\n        {4, 4, 2, true},\n        {2, 9, 1, false},\n        {1, 9, 0, true},\n    };\n\n    Result best;\n\n    for (int i = 0; i < (int)paramsList.size(); ++i) {\n        if (i > 0 && elapsed() > 1.75) break;\n        Result cur = simulate_strategy(init, paramsList[i]);\n        if (cur.energy < best.energy ||\n            (cur.energy == best.energy && cur.ops.size() < best.ops.size())) {\n            best = std::move(cur);\n        }\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXV = 1600;\nstatic constexpr long long INF_NUM = (1LL << 62);\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = chrono::steady_clock::now().time_since_epoch().count()) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next() % (uint64_t)n); }\n};\n\nstruct Score {\n    long long num;\n    int L;\n};\n\nstatic inline bool better_score(const Score& a, const Score& b) {\n    __int128 lhs = (__int128)a.num * b.L;\n    __int128 rhs = (__int128)b.num * a.L;\n    if (lhs != rhs) return lhs < rhs;\n    return a.L < b.L;\n}\n\nstruct TreeCand {\n    vector<int> parent;\n    Score score;\n};\n\nint N, Vn;\nvector<int> graph_[MAXV];\nvector<int> children_[MAXV];\nint dirt_[MAXV];\nlong long imp_raw_[MAXV];\nlong long imp_smooth_[MAXV];\n\nint sz_[MAXV];\nlong long subImp_[MAXV];\nlong long subD_[MAXV];\n\nint firstOcc_[MAXV];\nint lastOcc_[MAXV];\nlong long gapAcc_[MAXV];\n\nvector<int> posbuf;\nXorShift64 rng;\n\ninline int vid(int r, int c) { return r * N + c; }\n\ninline char move_char(int a, int b) {\n    if (b == a + 1) return 'R';\n    if (b == a - 1) return 'L';\n    if (b == a + N) return 'D';\n    return 'U';\n}\n\ninline long long noise_rand(long long noise) {\n    if (noise == 0) return 0;\n    return (long long)(rng.next() % (uint64_t)(2 * noise + 1)) - noise;\n}\n\nScore evaluate_parent(const vector<int>& parent, const long long* orderImp, string* routeOut = nullptr) {\n    for (int i = 0; i < Vn; i++) children_[i].clear();\n    for (int v = 1; v < Vn; v++) children_[parent[v]].push_back(v);\n\n    auto dfs1 = [&](auto&& self, int u) -> void {\n        sz_[u] = 1;\n        subImp_[u] = orderImp[u];\n        subD_[u] = dirt_[u];\n        for (int c : children_[u]) self(self, c);\n\n        sort(children_[u].begin(), children_[u].end(), [&](int a, int b) {\n            __int128 lhs = (__int128)subImp_[a] * sz_[b];\n            __int128 rhs = (__int128)subImp_[b] * sz_[a];\n            if (lhs != rhs) return lhs > rhs;   // higher density first\n            if (subD_[a] != subD_[b]) return subD_[a] > subD_[b];\n            return a < b;\n        });\n\n        for (int c : children_[u]) {\n            sz_[u] += sz_[c];\n            subImp_[u] += subImp_[c];\n            subD_[u] += subD_[c];\n        }\n    };\n    dfs1(dfs1, 0);\n\n    posbuf.clear();\n    posbuf.reserve(2 * Vn);\n    posbuf.push_back(0);\n\n    string route;\n    if (routeOut) route.reserve(2 * (Vn - 1));\n\n    auto dfs2 = [&](auto&& self, int u) -> void {\n        for (int c : children_[u]) {\n            posbuf.push_back(c);\n            if (routeOut) route.push_back(move_char(u, c));\n            self(self, c);\n            posbuf.push_back(u);\n            if (routeOut) route.push_back(move_char(c, u));\n        }\n    };\n    dfs2(dfs2, 0);\n\n    int L = (int)posbuf.size() - 1;\n    fill(firstOcc_, firstOcc_ + Vn, -1);\n    fill(gapAcc_, gapAcc_ + Vn, 0LL);\n\n    long long num = 0;\n    for (int t = 1; t <= L; t++) {\n        int x = posbuf[t];\n        if (firstOcc_[x] == -1) {\n            firstOcc_[x] = t;\n        } else {\n            long long g = t - lastOcc_[x];\n            gapAcc_[x] += g * (g - 1) / 2;\n        }\n        lastOcc_[x] = t;\n    }\n    for (int x = 0; x < Vn; x++) {\n        if (firstOcc_[x] == -1) return {INF_NUM, L};\n        long long g = firstOcc_[x] + L - lastOcc_[x];\n        gapAcc_[x] += g * (g - 1) / 2;\n        num += gapAcc_[x] * 1LL * dirt_[x];\n    }\n\n    if (routeOut) *routeOut = std::move(route);\n    return {num, L};\n}\n\nvoid refresh_topology(const vector<int>& parent, vector<int>& tin, vector<int>& tout, vector<int>& depth) {\n    for (int i = 0; i < Vn; i++) children_[i].clear();\n    for (int v = 1; v < Vn; v++) children_[parent[v]].push_back(v);\n\n    int timer = 0;\n    auto dfs = [&](auto&& self, int u, int dep) -> void {\n        tin[u] = timer++;\n        depth[u] = dep;\n        for (int c : children_[u]) self(self, c, dep + 1);\n        tout[u] = timer;\n    };\n    dfs(dfs, 0, 0);\n}\n\nvector<int> gen_weighted_dfs(const long long* imp, long long noise) {\n    vector<int> parent(Vn, -1);\n    vector<char> vis(Vn, 0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        vis[u] = 1;\n        array<pair<long long, int>, 4> cand;\n        int m = 0;\n        for (int to : graph_[u]) cand[m++] = {imp[to] + noise_rand(noise), to};\n        sort(cand.begin(), cand.begin() + m, [](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        for (int i = 0; i < m; i++) {\n            int to = cand[i].second;\n            if (!vis[to]) {\n                parent[to] = u;\n                self(self, to);\n            }\n        }\n    };\n    dfs(dfs, 0);\n    return parent;\n}\n\nvector<int> gen_prim(const long long* imp, long long noise, int depthPenalty) {\n    struct Node {\n        long long key;\n        uint64_t tie;\n        int from, to;\n        bool operator<(const Node& other) const {\n            if (key != other.key) return key < other.key;\n            return tie < other.tie;\n        }\n    };\n\n    vector<int> parent(Vn, -1), depth(Vn, 0);\n    vector<char> used(Vn, 0);\n    priority_queue<Node> pq;\n\n    used[0] = 1;\n    int cnt = 1;\n\n    auto push_edges = [&](int u) {\n        for (int to : graph_[u]) {\n            if (!used[to]) {\n                long long key = imp[to] - 1LL * depthPenalty * depth[u] + noise_rand(noise);\n                pq.push({key, rng.next(), u, to});\n            }\n        }\n    };\n    push_edges(0);\n\n    while (cnt < Vn && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n        if (used[cur.to]) continue;\n        used[cur.to] = 1;\n        parent[cur.to] = cur.from;\n        depth[cur.to] = depth[cur.from] + 1;\n        cnt++;\n        push_edges(cur.to);\n    }\n\n    if (cnt < Vn) return gen_weighted_dfs(imp, 0);\n    return parent;\n}\n\nvoid consider_pool(vector<TreeCand>& pool, const vector<int>& parent, const Score& score, int maxPool = 4) {\n    if ((int)pool.size() >= maxPool && !better_score(score, pool.back().score)) return;\n    pool.push_back({parent, score});\n    sort(pool.begin(), pool.end(), [](const TreeCand& a, const TreeCand& b) {\n        return better_score(a.score, b.score);\n    });\n    if ((int)pool.size() > maxPool) pool.pop_back();\n}\n\nvector<int> random_tree() {\n    bool useDFS = (rng.next() & 1);\n    const long long* imp = ((rng.next() & 1) ? imp_raw_ : imp_smooth_);\n    if (useDFS) {\n        static const long long noises[] = {0, 5000, 10000, 20000, 40000, 80000};\n        long long noise = noises[rng.next_int((int)(sizeof(noises) / sizeof(noises[0])))];\n        return gen_weighted_dfs(imp, noise);\n    } else {\n        static const long long noises[] = {0, 10000, 30000, 60000};\n        static const int pens[] = {0, 100, 300, 600};\n        long long noise = noises[rng.next_int((int)(sizeof(noises) / sizeof(noises[0])))];\n        int pen = pens[rng.next_int((int)(sizeof(pens) / sizeof(pens[0])))];\n        return gen_prim(imp, noise, pen);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<string> h(N - 1), vwall(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vwall[i];\n\n    Vn = N * N;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> dirt_[vid(i, j)];\n        }\n    }\n\n    for (int i = 0; i < Vn; i++) graph_[i].clear();\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int a = vid(i, j);\n            if (i + 1 < N && h[i][j] == '0') {\n                int b = vid(i + 1, j);\n                graph_[a].push_back(b);\n                graph_[b].push_back(a);\n            }\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int b = vid(i, j + 1);\n                graph_[a].push_back(b);\n                graph_[b].push_back(a);\n            }\n        }\n    }\n\n    for (int u = 0; u < Vn; u++) {\n        long long s = 0;\n        for (int to : graph_[u]) s += dirt_[to];\n        imp_raw_[u] = 100LL * dirt_[u];\n        imp_smooth_[u] = 100LL * dirt_[u] + 35LL * s;\n    }\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    const double TL = 1.92;\n\n    vector<TreeCand> pool;\n\n    // Initial candidates\n    {\n        const long long* imps[2] = {imp_raw_, imp_smooth_};\n\n        for (int t = 0; t < 2; t++) {\n            const long long* imp = imps[t];\n            vector<long long> dfsNoises = {0, 5000, 20000, 60000};\n            for (long long noise : dfsNoises) {\n                int reps = (noise == 0 ? 1 : 2);\n                for (int rep = 0; rep < reps; rep++) {\n                    auto p = gen_weighted_dfs(imp, noise);\n                    auto s = evaluate_parent(p, imp_smooth_);\n                    consider_pool(pool, p, s);\n                }\n            }\n\n            vector<long long> primNoises = {0, 10000, 40000};\n            vector<int> pens = {0, 150, 400};\n            for (long long noise : primNoises) {\n                for (int pen : pens) {\n                    auto p = gen_prim(imp, noise, pen);\n                    auto s = evaluate_parent(p, imp_smooth_);\n                    consider_pool(pool, p, s);\n                }\n            }\n        }\n    }\n\n    if (pool.empty()) {\n        auto p = gen_weighted_dfs(imp_smooth_, 0);\n        auto s = evaluate_parent(p, imp_smooth_);\n        consider_pool(pool, p, s);\n    }\n\n    TreeCand best = pool[0];\n    vector<int> currentParent = best.parent;\n    Score currentScore = best.score;\n\n    vector<int> tin(Vn), tout(Vn), depth(Vn);\n    refresh_topology(currentParent, tin, tout, depth);\n\n    int stall = 0;\n    int iter = 0;\n\n    while (true) {\n        if ((iter++ & 63) == 0 && elapsed() > TL) break;\n\n        if (stall >= 250) {\n            if (!pool.empty() && rng.next_int(100) < 70) {\n                int lim = min(3, (int)pool.size());\n                int idx = rng.next_int(lim);\n                currentParent = pool[idx].parent;\n                currentScore = pool[idx].score;\n            } else {\n                auto p = random_tree();\n                auto s = evaluate_parent(p, imp_smooth_);\n                consider_pool(pool, p, s);\n                currentParent = std::move(p);\n                currentScore = s;\n                if (better_score(currentScore, best.score)) {\n                    best = {currentParent, currentScore};\n                }\n            }\n            refresh_topology(currentParent, tin, tout, depth);\n            stall = 0;\n            continue;\n        }\n\n        int u = -1, w = -1;\n        bool ok = false;\n\n        for (int tries = 0; tries < 20 && !ok; tries++) {\n            u = 1 + rng.next_int(Vn - 1);\n\n            int opts[4];\n            int m = 0;\n            for (int to : graph_[u]) {\n                if (to == currentParent[u]) continue;\n                if (tin[u] <= tin[to] && tout[to] <= tout[u]) continue; // descendant => cycle\n                opts[m++] = to;\n            }\n            if (m == 0) continue;\n\n            if (m == 1 || rng.next_int(100) < 30) {\n                w = opts[rng.next_int(m)];\n            } else {\n                long long bestKey = LLONG_MIN;\n                int bestTo = opts[0];\n                for (int i = 0; i < m; i++) {\n                    int to = opts[i];\n                    long long key = imp_smooth_[to] - 250LL * depth[to] + (long long)(rng.next() % 10000);\n                    if (key > bestKey) {\n                        bestKey = key;\n                        bestTo = to;\n                    }\n                }\n                w = bestTo;\n            }\n            ok = true;\n        }\n\n        if (!ok) {\n            stall++;\n            continue;\n        }\n\n        vector<int> candParent = currentParent;\n        candParent[u] = w;\n        Score candScore = evaluate_parent(candParent, imp_smooth_);\n\n        if (better_score(candScore, currentScore)) {\n            currentParent.swap(candParent);\n            currentScore = candScore;\n            refresh_topology(currentParent, tin, tout, depth);\n            stall = 0;\n\n            consider_pool(pool, currentParent, currentScore);\n            if (better_score(currentScore, best.score)) {\n                best = {currentParent, currentScore};\n            }\n        } else {\n            stall++;\n        }\n    }\n\n    // Final route: compare two child-order metrics and output the better one.\n    string routeA, routeB;\n    Score sA = evaluate_parent(best.parent, imp_smooth_, &routeA);\n    Score sB = evaluate_parent(best.parent, imp_raw_, &routeB);\n\n    if (better_score(sB, sA)) {\n        cout << routeB << '\\n';\n    } else {\n        cout << routeA << '\\n';\n    }\n\n    return 0;\n}","ahc028":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    int n;\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n_) {\n        n = n_;\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool same(int a, int b) { return find(a) == find(b); }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int INF = 1e9;\n    static constexpr int MAXM = 205;\n    static constexpr int POS = 225; // 15*15\n\n    int N, M;\n    int si, sj;\n    int startPos;\n\n    vector<string> A;\n    vector<string> words;\n    vector<array<int, 5>> wch;\n\n    array<vector<int>, 26> occ;\n    int man[POS][POS];\n\n    int ov[MAXM][MAXM];\n    int startWordCost[MAXM];\n    int fromCharCost[26][MAXM][5];\n    int transCost[MAXM][MAXM];\n\n    unordered_map<int, int> codeToId;\n\n    uint32_t baseSeed = 1;\n\n    static int encode5(const string& s) {\n        int x = 0;\n        for (char c : s) x = x * 26 + (c - 'A');\n        return x;\n    }\n\n    int distPos(int p, int q) const {\n        return man[p][q];\n    }\n\n    void read() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        cin >> si >> sj;\n        startPos = si * N + sj;\n\n        A.resize(N);\n        for (int i = 0; i < N; i++) cin >> A[i];\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    void buildSeed() {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (auto& row : A) for (char c : row) mix((uint64_t)c);\n        for (auto& s : words) for (char c : s) mix((uint64_t)c);\n        baseSeed = (uint32_t)(h ^ (h >> 32));\n        if (baseSeed == 0) baseSeed = 1;\n    }\n\n    void precomputeKeyboard() {\n        for (auto& v : occ) v.clear();\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                occ[A[i][j] - 'A'].push_back(id);\n            }\n        }\n        for (int p = 0; p < N * N; p++) {\n            int pi = p / N, pj = p % N;\n            for (int q = 0; q < N * N; q++) {\n                int qi = q / N, qj = q % N;\n                man[p][q] = abs(pi - qi) + abs(pj - qj);\n            }\n        }\n    }\n\n    int calcOverlap(const string& a, const string& b) const {\n        for (int len = 4; len >= 1; len--) {\n            bool ok = true;\n            for (int k = 0; k < len; k++) {\n                if (a[5 - len + k] != b[k]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return len;\n        }\n        return 0;\n    }\n\n    int typeCostFromSources(const vector<int>& srcPos, const vector<int>& srcCost,\n                            const array<int, 5>& w, int st) const {\n        vector<int> prevPos = srcPos;\n        vector<int> prevCost = srcCost;\n\n        for (int k = st; k < 5; k++) {\n            const auto& curPos = occ[w[k]];\n            vector<int> curCost(curPos.size(), INF);\n            for (int ci = 0; ci < (int)curPos.size(); ci++) {\n                int q = curPos[ci];\n                int best = INF;\n                for (int pi = 0; pi < (int)prevPos.size(); pi++) {\n                    int p = prevPos[pi];\n                    best = min(best, prevCost[pi] + distPos(p, q) + 1);\n                }\n                curCost[ci] = best;\n            }\n            prevPos = curPos;\n            prevCost.swap(curCost);\n        }\n\n        int ans = INF;\n        for (int x : prevCost) ans = min(ans, x);\n        return ans;\n    }\n\n    void precomputeCosts() {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                ov[i][j] = (i == j ? 0 : calcOverlap(words[i], words[j]));\n            }\n        }\n\n        {\n            vector<int> srcPos = {startPos};\n            vector<int> srcCost = {0};\n            for (int i = 0; i < M; i++) {\n                startWordCost[i] = typeCostFromSources(srcPos, srcCost, wch[i], 0);\n            }\n        }\n\n        for (int c = 0; c < 26; c++) {\n            vector<int> srcPos = occ[c];\n            vector<int> srcCost(srcPos.size(), 0);\n            for (int j = 0; j < M; j++) {\n                for (int st = 0; st < 5; st++) {\n                    fromCharCost[c][j][st] = typeCostFromSources(srcPos, srcCost, wch[j], st);\n                }\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            int lastc = wch[i][4];\n            for (int j = 0; j < M; j++) {\n                if (i == j) {\n                    transCost[i][j] = INF / 4;\n                    continue;\n                }\n                int o = ov[i][j];\n                if (o == 0) transCost[i][j] = fromCharCost[lastc][j][0];\n                else transCost[i][j] = fromCharCost[wch[j][o - 1]][j][o];\n            }\n        }\n\n        codeToId.clear();\n        codeToId.reserve(M * 2 + 10);\n        codeToId.max_load_factor(0.7f);\n        for (int i = 0; i < M; i++) codeToId[encode5(words[i])] = i;\n    }\n\n    string buildString(const vector<int>& perm) const {\n        if (perm.empty()) return \"\";\n        string s;\n        s.reserve(5 * (int)perm.size());\n        s += words[perm[0]];\n        for (int i = 1; i < (int)perm.size(); i++) {\n            int o = ov[perm[i - 1]][perm[i]];\n            s.append(words[perm[i]].begin() + o, words[perm[i]].end());\n        }\n        return s;\n    }\n\n    bool coversAll(const string& s) const {\n        if ((int)s.size() < 5) return false;\n        vector<char> seen(M, 0);\n        int got = 0;\n\n        constexpr int POW4 = 26 * 26 * 26 * 26;\n        int code = 0;\n        for (int i = 0; i < 5; i++) code = code * 26 + (s[i] - 'A');\n\n        auto it = codeToId.find(code);\n        if (it != codeToId.end() && !seen[it->second]) {\n            seen[it->second] = 1;\n            got++;\n        }\n\n        for (int i = 5; i < (int)s.size(); i++) {\n            code = (code % POW4) * 26 + (s[i] - 'A');\n            auto jt = codeToId.find(code);\n            if (jt != codeToId.end() && !seen[jt->second]) {\n                seen[jt->second] = 1;\n                got++;\n            }\n        }\n\n        return got == M;\n    }\n\n    int exactCostString(const string& s) const {\n        if (s.empty()) return 0;\n\n        const auto& firstPos = occ[s[0] - 'A'];\n        vector<int> dpPrev(firstPos.size());\n\n        for (int i = 0; i < (int)firstPos.size(); i++) {\n            dpPrev[i] = distPos(startPos, firstPos[i]) + 1;\n        }\n\n        for (int t = 1; t < (int)s.size(); t++) {\n            const auto& prevPos = occ[s[t - 1] - 'A'];\n            const auto& curPos = occ[s[t] - 'A'];\n            vector<int> dpCur(curPos.size(), INF);\n\n            for (int ci = 0; ci < (int)curPos.size(); ci++) {\n                int q = curPos[ci];\n                int best = INF;\n                for (int pi = 0; pi < (int)prevPos.size(); pi++) {\n                    int p = prevPos[pi];\n                    best = min(best, dpPrev[pi] + distPos(p, q) + 1);\n                }\n                dpCur[ci] = best;\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        int ans = INF;\n        for (int x : dpPrev) ans = min(ans, x);\n        return ans;\n    }\n\n    pair<int, vector<int>> exactCostAndPath(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n\n        const auto& firstPos = occ[s[0] - 'A'];\n        vector<int> dpPrev(firstPos.size());\n        parent[0].assign(firstPos.size(), -1);\n\n        for (int i = 0; i < (int)firstPos.size(); i++) {\n            dpPrev[i] = distPos(startPos, firstPos[i]) + 1;\n        }\n\n        for (int t = 1; t < L; t++) {\n            const auto& prevPos = occ[s[t - 1] - 'A'];\n            const auto& curPos = occ[s[t] - 'A'];\n            vector<int> dpCur(curPos.size(), INF);\n            parent[t].assign(curPos.size(), -1);\n\n            for (int ci = 0; ci < (int)curPos.size(); ci++) {\n                int q = curPos[ci];\n                int best = INF;\n                int bestp = -1;\n                for (int pi = 0; pi < (int)prevPos.size(); pi++) {\n                    int p = prevPos[pi];\n                    int cand = dpPrev[pi] + distPos(p, q) + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bestp = pi;\n                    }\n                }\n                dpCur[ci] = best;\n                parent[t][ci] = bestp;\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        int best = INF, idx = -1;\n        for (int i = 0; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < best) {\n                best = dpPrev[i];\n                idx = i;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = occ[s[L - 1] - 'A'][idx];\n        for (int t = L - 1; t >= 1; t--) {\n            idx = parent[t][idx];\n            path[t - 1] = occ[s[t - 1] - 'A'][idx];\n        }\n        return {best, path};\n    }\n\n    long long approxPermCost(const vector<int>& perm) const {\n        if (perm.empty()) return 0;\n        long long cost = startWordCost[perm[0]];\n        for (int i = 1; i < (int)perm.size(); i++) {\n            cost += transCost[perm[i - 1]][perm[i]];\n        }\n        return cost;\n    }\n\n    long long relocateDelta(const vector<int>& p, int a, int b) const {\n        int n = (int)p.size();\n        if (a == b) return 0;\n        int x = p[a];\n\n        auto startc = [&](int v) -> long long {\n            return startWordCost[v];\n        };\n        auto edgec = [&](int u, int v) -> long long {\n            return transCost[u][v];\n        };\n\n        int A = (a > 0 ? p[a - 1] : -1);\n        int B = (a + 1 < n ? p[a + 1] : -1);\n\n        long long delta = 0;\n\n        // remove x\n        if (A == -1) {\n            delta -= startc(x);\n            if (B != -1) {\n                delta += startc(B);\n                delta -= edgec(x, B);\n            }\n        } else {\n            delta -= edgec(A, x);\n            if (B != -1) {\n                delta += edgec(A, B);\n                delta -= edgec(x, B);\n            }\n        }\n\n        // insert x into array after removal, at position b (0..n-1)\n        int C, D;\n        if (b <= a - 1) {\n            C = (b > 0 ? p[b - 1] : -1);\n            D = p[b];\n        } else { // b > a\n            C = p[b];\n            D = (b + 1 < n ? p[b + 1] : -1);\n        }\n\n        if (C == -1) {\n            delta += startc(x);\n            if (D != -1) {\n                delta += edgec(x, D);\n                delta -= startc(D);\n            }\n        } else {\n            delta += edgec(C, x);\n            if (D != -1) {\n                delta += edgec(x, D);\n                delta -= edgec(C, D);\n            }\n        }\n\n        return delta;\n    }\n\n    void applyRelocate(vector<int>& p, int a, int b) const {\n        int x = p[a];\n        p.erase(p.begin() + a);\n        p.insert(p.begin() + b, x);\n    }\n\n    vector<int> localSearchApprox(vector<int> p) const {\n        int n = (int)p.size();\n        if (n <= 1) return p;\n\n        for (int iter = 0; iter < 500; iter++) {\n            long long bestDelta = 0;\n            int besta = -1, bestb = -1;\n\n            for (int a = 0; a < n; a++) {\n                for (int b = 0; b < n; b++) {\n                    if (a == b) continue;\n                    long long d = relocateDelta(p, a, b);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        besta = a;\n                        bestb = b;\n                    }\n                }\n            }\n\n            if (bestDelta >= 0) break;\n            applyRelocate(p, besta, bestb);\n        }\n\n        return p;\n    }\n\n    vector<int> initGreedyEdge(uint32_t seed, bool randomized) const {\n        struct E {\n            int u, v, ov, cost;\n        };\n        vector<E> edges;\n        edges.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                edges.push_back({i, j, ov[i][j], transCost[i][j]});\n            }\n        }\n\n        mt19937 rng(seed);\n        if (randomized) shuffle(edges.begin(), edges.end(), rng);\n\n        stable_sort(edges.begin(), edges.end(), [&](const E& a, const E& b) {\n            if (a.ov != b.ov) return a.ov > b.ov;\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        vector<int> in(M, -1), out(M, -1);\n        DSU dsu(M);\n        int used = 0;\n\n        for (const auto& e : edges) {\n            if (out[e.u] != -1) continue;\n            if (in[e.v] != -1) continue;\n            if (dsu.same(e.u, e.v)) continue;\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n            used++;\n            if (used == 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> perm;\n        perm.reserve(M);\n        vector<char> seen(M, 0);\n        int cur = head;\n        while (cur != -1 && !seen[cur]) {\n            perm.push_back(cur);\n            seen[cur] = 1;\n            cur = out[cur];\n        }\n\n        for (int i = 0; i < M; i++) if (!seen[i]) perm.push_back(i);\n        return perm;\n    }\n\n    vector<int> initCheapestInsertion(uint32_t seed, bool randomized) const {\n        mt19937 rng(seed);\n\n        if (M == 1) return vector<int>{0};\n\n        struct PairCand {\n            long long cost;\n            int a, b;\n        };\n        vector<PairCand> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                pairs.push_back({(long long)startWordCost[i] + transCost[i][j], i, j});\n            }\n        }\n        sort(pairs.begin(), pairs.end(), [](const PairCand& x, const PairCand& y) {\n            if (x.cost != y.cost) return x.cost < y.cost;\n            if (x.a != y.a) return x.a < y.a;\n            return x.b < y.b;\n        });\n\n        int pick = 0;\n        if (randomized) {\n            int lim = min<int>(8, pairs.size());\n            pick = uniform_int_distribution<int>(0, lim - 1)(rng);\n        }\n\n        vector<int> perm = {pairs[pick].a, pairs[pick].b};\n        vector<char> used(M, 0);\n        used[pairs[pick].a] = used[pairs[pick].b] = 1;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                long long inc;\n                int x, pos;\n            };\n            vector<Cand> bests;\n            int keep = randomized ? 6 : 1;\n\n            auto push_cand = [&](Cand c) {\n                bests.push_back(c);\n                sort(bests.begin(), bests.end(), [](const Cand& a, const Cand& b) {\n                    if (a.inc != b.inc) return a.inc < b.inc;\n                    if (a.x != b.x) return a.x < b.x;\n                    return a.pos < b.pos;\n                });\n                if ((int)bests.size() > keep) bests.pop_back();\n            };\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                // front\n                push_cand({(long long)startWordCost[x] + transCost[x][perm[0]] - startWordCost[perm[0]], x, 0});\n                // middle\n                for (int i = 1; i < (int)perm.size(); i++) {\n                    long long inc = (long long)transCost[perm[i - 1]][x] + transCost[x][perm[i]] - transCost[perm[i - 1]][perm[i]];\n                    push_cand({inc, x, i});\n                }\n                // back\n                push_cand({(long long)transCost[perm.back()][x], x, (int)perm.size()});\n            }\n\n            int idx = 0;\n            if (randomized) idx = uniform_int_distribution<int>(0, (int)bests.size() - 1)(rng);\n            auto c = bests[idx];\n            perm.insert(perm.begin() + c.pos, c.x);\n            used[c.x] = 1;\n        }\n\n        return perm;\n    }\n\n    vector<int> initTwoEnded(uint32_t seed, bool randomized) const {\n        mt19937 rng(seed);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (startWordCost[a] != startWordCost[b]) return startWordCost[a] < startWordCost[b];\n            return a < b;\n        });\n\n        int start = ord[0];\n        if (randomized) {\n            int lim = min(8, M);\n            start = ord[uniform_int_distribution<int>(0, lim - 1)(rng)];\n        }\n\n        vector<int> perm = {start};\n        vector<char> used(M, 0);\n        used[start] = 1;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                long long inc;\n                int x;\n                bool front;\n            };\n            vector<Cand> bests;\n            int keep = randomized ? 6 : 1;\n\n            auto push_cand = [&](Cand c) {\n                bests.push_back(c);\n                sort(bests.begin(), bests.end(), [](const Cand& a, const Cand& b) {\n                    if (a.inc != b.inc) return a.inc < b.inc;\n                    if (a.x != b.x) return a.x < b.x;\n                    return a.front < b.front;\n                });\n                if ((int)bests.size() > keep) bests.pop_back();\n            };\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                long long frontInc = (long long)startWordCost[x] + transCost[x][perm[0]] - startWordCost[perm[0]];\n                long long backInc = (long long)transCost[perm.back()][x];\n                push_cand({frontInc, x, true});\n                push_cand({backInc, x, false});\n            }\n\n            int idx = 0;\n            if (randomized) idx = uniform_int_distribution<int>(0, (int)bests.size() - 1)(rng);\n            auto c = bests[idx];\n            if (c.front) perm.insert(perm.begin(), c.x);\n            else perm.push_back(c.x);\n            used[c.x] = 1;\n        }\n\n        return perm;\n    }\n\n    vector<int> exactRefine(vector<int> perm, bool needCoverage, int maxIter, int topKPerA) const {\n        if ((int)perm.size() <= 1) return perm;\n\n        string curS = buildString(perm);\n        if (needCoverage && !coversAll(curS)) return perm;\n        int curT = exactCostString(curS);\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            struct MCand {\n                long long approxDelta;\n                int a, b;\n            };\n            vector<MCand> candMoves;\n\n            int n = (int)perm.size();\n            for (int a = 0; a < n; a++) {\n                vector<pair<long long, int>> bests;\n                for (int b = 0; b < n; b++) {\n                    if (a == b) continue;\n                    long long d = relocateDelta(perm, a, b);\n                    bests.push_back({d, b});\n                }\n                sort(bests.begin(), bests.end());\n                int lim = min<int>(topKPerA, bests.size());\n                for (int i = 0; i < lim; i++) {\n                    candMoves.push_back({bests[i].first, a, bests[i].second});\n                }\n            }\n\n            sort(candMoves.begin(), candMoves.end(), [](const MCand& x, const MCand& y) {\n                if (x.approxDelta != y.approxDelta) return x.approxDelta < y.approxDelta;\n                if (x.a != y.a) return x.a < y.a;\n                return x.b < y.b;\n            });\n            if ((int)candMoves.size() > 400) candMoves.resize(400);\n\n            int bestT = curT;\n            int besta = -1, bestb = -1;\n            string bestS;\n\n            for (auto& mv : candMoves) {\n                vector<int> np = perm;\n                applyRelocate(np, mv.a, mv.b);\n                string ns = buildString(np);\n                if (needCoverage && !coversAll(ns)) continue;\n                int nt = exactCostString(ns);\n                if (nt < bestT) {\n                    bestT = nt;\n                    besta = mv.a;\n                    bestb = mv.b;\n                    bestS = move(ns);\n                }\n            }\n\n            if (besta == -1) break;\n            applyRelocate(perm, besta, bestb);\n            curT = bestT;\n            curS = move(bestS);\n        }\n\n        return perm;\n    }\n\n    vector<int> greedyDelete(vector<int> perm) const {\n        if (perm.empty()) return perm;\n\n        string curS = buildString(perm);\n        int curT = exactCostString(curS);\n\n        while (true) {\n            int bestT = curT;\n            int bestK = -1;\n            string bestS;\n\n            for (int k = 0; k < (int)perm.size(); k++) {\n                vector<int> np = perm;\n                np.erase(np.begin() + k);\n                string ns = buildString(np);\n                if (!coversAll(ns)) continue;\n                int nt = exactCostString(ns);\n                if (nt < bestT) {\n                    bestT = nt;\n                    bestK = k;\n                    bestS = move(ns);\n                }\n            }\n\n            if (bestK == -1) break;\n            perm.erase(perm.begin() + bestK);\n            curT = bestT;\n            curS = move(bestS);\n        }\n\n        return perm;\n    }\n\n    void solve() {\n        read();\n        buildSeed();\n        precomputeKeyboard();\n        precomputeCosts();\n\n        struct Candidate {\n            vector<int> perm;\n            long long approx;\n            int exact;\n        };\n        vector<Candidate> cands;\n\n        auto addCandidate = [&](vector<int> p) {\n            p = localSearchApprox(move(p));\n            string s = buildString(p);\n            int ex = exactCostString(s);\n            cands.push_back({move(p), approxPermCost(cands.empty() ? vector<int>{} : cands.back().perm), ex});\n            cands.back().approx = approxPermCost(cands.back().perm);\n        };\n\n        addCandidate(initGreedyEdge(baseSeed + 11, false));\n        addCandidate(initGreedyEdge(baseSeed + 12, true));\n        addCandidate(initGreedyEdge(baseSeed + 13, true));\n\n        addCandidate(initCheapestInsertion(baseSeed + 21, false));\n        addCandidate(initCheapestInsertion(baseSeed + 22, true));\n        addCandidate(initCheapestInsertion(baseSeed + 23, true));\n\n        addCandidate(initTwoEnded(baseSeed + 31, false));\n        addCandidate(initTwoEnded(baseSeed + 32, true));\n\n        sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.exact != b.exact) return a.exact < b.exact;\n            return a.approx < b.approx;\n        });\n\n        int take = min<int>(2, cands.size());\n\n        vector<int> bestPerm = cands[0].perm;\n        int bestExact = exactCostString(buildString(bestPerm));\n\n        for (int idx = 0; idx < take; idx++) {\n            vector<int> p = cands[idx].perm;\n\n            p = exactRefine(move(p), false, 3, 2);\n            p = greedyDelete(move(p));\n            p = exactRefine(move(p), true, 2, 2);\n            p = greedyDelete(move(p));\n\n            string s = buildString(p);\n            if (!coversAll(s)) continue;\n            int ex = exactCostString(s);\n            if (ex < bestExact) {\n                bestExact = ex;\n                bestPerm = move(p);\n            }\n        }\n\n        string finalS = buildString(bestPerm);\n        if (!coversAll(finalS)) {\n            // Fallback to best full-permutation candidate if somehow postprocess broke it.\n            bestPerm = cands[0].perm;\n            finalS = buildString(bestPerm);\n        }\n\n        auto [cost, path] = exactCostAndPath(finalS);\n\n        for (int id : path) {\n            cout << (id / N) << ' ' << (id % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXQ = 64;\nstatic constexpr int WORDS = 7;   // 7*64 = 448 >= 400\n\nusing ull = unsigned long long;\nusing Mask = array<ull, WORDS>;\n\nstruct Placement {\n    int di, dj;\n    Mask mask{};\n    array<unsigned char, MAXQ> contrib{};\n};\n\nstruct Field {\n    int sz = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> pls;\n};\n\nstruct State {\n    vector<int> choice;                  // chosen placement per field\n    array<short, MAXQ> setsum{};         // predicted v(S) for each set query\n    vector<short> drillsum;              // predicted exact count on drilled cells\n    int pen = 0;                         // sum of squared errors on drilled exact counts\n    double div = 0.0;                    // divination score\n};\n\nstruct UnionSummary {\n    vector<Mask> masks;\n    vector<double> weights;\n    bool hasPlausible = false;\n    Mask bestMask{};\n    double bestWeight = 0.0;\n    double maxEntropy = 0.0;\n    int bestCell = -1;\n};\n\nstruct Solver {\n    int N, M, NN;\n    double eps, alpha;\n    int totalArea = 0;\n    int maxOps;\n    int ops = 0;\n\n    vector<Field> fields;\n\n    int Qall;\n    vector<vector<int>> queryCells;          // cell indices\n    vector<int> qSize, qResp;\n    vector<char> qKnown;\n    vector<vector<double>> qScore;           // qScore[q][predicted_sum]\n\n    vector<array<int,4>> cellQids;           // row, col, mod2, mod3\n\n    vector<int> drilledCells;\n    vector<int> drilledObs;\n    vector<int> cellObs;                     // -1 if unknown\n    vector<char> drilledFlag;\n\n    vector<State> pool;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point stTime;\n\n    Solver(): rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    static inline void mask_clear(Mask &m) {\n        m.fill(0);\n    }\n    static inline void mask_set(Mask &m, int idx) {\n        m[idx >> 6] |= (1ULL << (idx & 63));\n    }\n    static inline int mask_test(const Mask &m, int idx) {\n        return int((m[idx >> 6] >> (idx & 63)) & 1ULL);\n    }\n    static inline void mask_or_eq(Mask &a, const Mask &b) {\n        for (int i = 0; i < WORDS; i++) a[i] |= b[i];\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - stTime).count();\n    }\n\n    bool better(int p1, double d1, int p2, double d2) const {\n        if (p1 != p2) return p1 < p2;\n        return d1 + 1e-12 < d2;\n    }\n\n    int rand_int(int lim) {\n        return int(rng() % (uint64_t)lim);\n    }\n\n    void read_input() {\n        cin >> N >> M >> eps;\n        NN = N * N;\n        maxOps = 2 * NN;\n        alpha = 1.0 - 2.0 * eps;\n\n        fields.resize(M);\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            fields[k].sz = d;\n            fields[k].rel.resize(d);\n            int mxr = 0, mxc = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].rel[t] = {i, j};\n                mxr = max(mxr, i);\n                mxc = max(mxc, j);\n            }\n            fields[k].h = mxr + 1;\n            fields[k].w = mxc + 1;\n            totalArea += d;\n        }\n\n        cellObs.assign(NN, -1);\n        drilledFlag.assign(NN, 0);\n    }\n\n    void build_queries() {\n        // qid:\n        // [0, N) row\n        // [N, 2N) col\n        // [2N, 2N+4) mod2\n        // [2N+4, 2N+13) mod3\n        Qall = 2 * N + 13;\n        queryCells.assign(Qall, {});\n        qSize.assign(Qall, 0);\n        qResp.assign(Qall, 0);\n        qKnown.assign(Qall, 0);\n        qScore.assign(Qall, vector<double>(totalArea + 1, 0.0));\n        cellQids.resize(NN);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int idx = i * N + j;\n                int q0 = i;\n                int q1 = N + j;\n                int q2 = 2 * N + (i & 1) * 2 + (j & 1);\n                int q3 = 2 * N + 4 + (i % 3) * 3 + (j % 3);\n                cellQids[idx] = {q0, q1, q2, q3};\n                queryCells[q0].push_back(idx);\n                queryCells[q1].push_back(idx);\n                queryCells[q2].push_back(idx);\n                queryCells[q3].push_back(idx);\n            }\n        }\n        for (int q = 0; q < Qall; q++) qSize[q] = (int)queryCells[q].size();\n    }\n\n    void precompute_placements() {\n        for (int k = 0; k < M; k++) {\n            auto &f = fields[k];\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                    mask_clear(p.mask);\n                    p.contrib.fill(0);\n                    for (auto [ri, rj] : f.rel) {\n                        int ai = di + ri;\n                        int aj = dj + rj;\n                        int idx = ai * N + aj;\n                        mask_set(p.mask, idx);\n                        auto &arr = cellQids[idx];\n                        for (int t = 0; t < 4; t++) {\n                            p.contrib[arr[t]]++;\n                        }\n                    }\n                    f.pls.push_back(p);\n                }\n            }\n        }\n    }\n\n    int ask_set_query(const vector<int> &cells) {\n        cout << \"q \" << cells.size();\n        for (int idx : cells) {\n            cout << ' ' << (idx / N) << ' ' << (idx % N);\n        }\n        cout << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << ' ' << (idx % N) << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    bool answer_mask(const Mask &mask) {\n        vector<int> cells;\n        cells.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) {\n            if (mask_test(mask, idx)) cells.push_back(idx);\n        }\n        cout << \"a \" << cells.size();\n        for (int idx : cells) {\n            cout << ' ' << (idx / N) << ' ' << (idx % N);\n        }\n        cout << '\\n' << flush;\n        int res;\n        cin >> res;\n        ops++;\n        return res == 1;\n    }\n\n    void activate_queries(int l, int r) {\n        for (int q = l; q < r; q++) {\n            if (qKnown[q]) continue;\n            int y = ask_set_query(queryCells[q]);\n            qKnown[q] = 1;\n            qResp[q] = y;\n            double var = qSize[q] * eps * (1.0 - eps) + 0.25; // robustify rounding\n            for (int v = 0; v <= totalArea; v++) {\n                double mu = eps * qSize[q] + alpha * v;\n                double diff = y - mu;\n                qScore[q][v] = diff * diff / var;\n            }\n        }\n    }\n\n    State build_state(const vector<int> &choice) {\n        State st;\n        st.choice = choice;\n        st.setsum.fill(0);\n\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[choice[k]];\n            for (int q = 0; q < Qall; q++) {\n                st.setsum[q] += pl.contrib[q];\n            }\n        }\n\n        st.div = 0.0;\n        for (int q = 0; q < Qall; q++) st.div += qScore[q][st.setsum[q]];\n\n        int D = (int)drilledCells.size();\n        st.drillsum.assign(D, 0);\n        st.pen = 0;\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int s = 0;\n            for (int k = 0; k < M; k++) {\n                const auto &pl = fields[k].pls[choice[k]];\n                s += mask_test(pl.mask, idx);\n            }\n            st.drillsum[t] = (short)s;\n            int d = s - drilledObs[t];\n            st.pen += d * d;\n        }\n        return st;\n    }\n\n    void apply_move(State &st, int k, int newPid) {\n        int oldPid = st.choice[k];\n        if (oldPid == newPid) return;\n        const auto &oldPl = fields[k].pls[oldPid];\n        const auto &newPl = fields[k].pls[newPid];\n\n        for (int q = 0; q < Qall; q++) {\n            int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n            if (diff == 0) continue;\n            int oldv = st.setsum[q];\n            int newv = oldv + diff;\n            st.div += qScore[q][newv] - qScore[q][oldv];\n            st.setsum[q] = (short)newv;\n        }\n\n        int D = (int)drilledCells.size();\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int diff = mask_test(newPl.mask, idx) - mask_test(oldPl.mask, idx);\n            if (diff == 0) continue;\n            int oldv = st.drillsum[t];\n            int newv = oldv + diff;\n            int before = oldv - drilledObs[t];\n            int after = newv - drilledObs[t];\n            st.pen += after * after - before * before;\n            st.drillsum[t] = (short)newv;\n        }\n\n        st.choice[k] = newPid;\n    }\n\n    void hill_climb(State &st, int sweeps) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            bool changed = false;\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int kk = 0; kk < M; kk++) {\n                int k = ord[kk];\n                int oldPid = st.choice[k];\n                const auto &oldPl = fields[k].pls[oldPid];\n\n                int bestPid = oldPid;\n                int bestPen = st.pen;\n                double bestDiv = st.div;\n\n                int D = (int)drilledCells.size();\n\n                for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                    if (pid == oldPid) continue;\n                    const auto &newPl = fields[k].pls[pid];\n\n                    int candPen = st.pen;\n                    double candDiv = st.div;\n\n                    for (int q = 0; q < Qall; q++) {\n                        int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n                        if (diff == 0) continue;\n                        int oldv = st.setsum[q];\n                        int newv = oldv + diff;\n                        candDiv += qScore[q][newv] - qScore[q][oldv];\n                    }\n\n                    for (int t = 0; t < D; t++) {\n                        int idx = drilledCells[t];\n                        int diff = mask_test(newPl.mask, idx) - mask_test(oldPl.mask, idx);\n                        if (diff == 0) continue;\n                        int oldv = st.drillsum[t];\n                        int newv = oldv + diff;\n                        int before = oldv - drilledObs[t];\n                        int after = newv - drilledObs[t];\n                        candPen += after * after - before * before;\n                    }\n\n                    if (better(candPen, candDiv, bestPen, bestDiv)) {\n                        bestPen = candPen;\n                        bestDiv = candDiv;\n                        bestPid = pid;\n                    }\n                }\n\n                if (bestPid != oldPid) {\n                    apply_move(st, k, bestPid);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> random_seed() {\n        vector<int> choice(M);\n        for (int k = 0; k < M; k++) {\n            choice[k] = rand_int((int)fields[k].pls.size());\n        }\n        return choice;\n    }\n\n    vector<int> greedy_seed() {\n        vector<int> choice(M, 0);\n        array<short, MAXQ> cur{};\n        cur.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int id = 0; id < M; id++) {\n            int k = ord[id];\n            int bestPid = 0;\n            double bestDelta = 1e100;\n\n            for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                const auto &pl = fields[k].pls[pid];\n                double delta = 0.0;\n                for (int q = 0; q < Qall; q++) {\n                    int c = pl.contrib[q];\n                    if (!c) continue;\n                    int oldv = cur[q];\n                    int newv = oldv + c;\n                    delta += qScore[q][newv] - qScore[q][oldv];\n                }\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPid = pid;\n                }\n            }\n\n            choice[k] = bestPid;\n            const auto &pl = fields[k].pls[bestPid];\n            for (int q = 0; q < Qall; q++) cur[q] += pl.contrib[q];\n        }\n        return choice;\n    }\n\n    vector<int> perturbed_seed() {\n        if (pool.empty()) return random_seed();\n        int bases = min(3, (int)pool.size());\n        vector<int> choice = pool[rand_int(bases)].choice;\n\n        int changes = 1 + rand_int(max(1, min(3, M)));\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int t = 0; t < changes; t++) {\n            int k = ord[t];\n            int sz = (int)fields[k].pls.size();\n            if (sz <= 1) continue;\n            int cur = choice[k];\n            int np = rand_int(sz - 1);\n            if (np >= cur) np++;\n            choice[k] = np;\n        }\n        return choice;\n    }\n\n    bool contains_choice(const vector<vector<int>> &vv, const vector<int> &x) {\n        for (const auto &v : vv) {\n            if (v == x) return true;\n        }\n        return false;\n    }\n\n    void optimize_pool(int randomCnt, int pertCnt, int sweeps, bool useGreedy) {\n        vector<vector<int>> seeds;\n\n        for (const auto &st : pool) {\n            if (!contains_choice(seeds, st.choice)) seeds.push_back(st.choice);\n        }\n\n        if (useGreedy) {\n            int g = 6;\n            for (int t = 0; t < g; t++) {\n                auto s = greedy_seed();\n                if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n            }\n        }\n\n        for (int t = 0; t < pertCnt; t++) {\n            auto s = perturbed_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        for (int t = 0; t < randomCnt; t++) {\n            auto s = random_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        if (seeds.empty()) seeds.push_back(random_seed());\n\n        vector<State> cands;\n        cands.reserve(seeds.size());\n        for (auto &seed : seeds) {\n            State st = build_state(seed);\n            hill_climb(st, sweeps);\n            cands.push_back(move(st));\n        }\n\n        sort(cands.begin(), cands.end(), [&](const State &a, const State &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        pool.clear();\n        for (auto &st : cands) {\n            bool dup = false;\n            for (auto &kept : pool) {\n                if (kept.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) pool.push_back(move(st));\n            if ((int)pool.size() >= 10) break;\n        }\n    }\n\n    Mask union_of_choice(const vector<int> &choice) {\n        Mask u{};\n        mask_clear(u);\n        for (int k = 0; k < M; k++) {\n            mask_or_eq(u, fields[k].pls[choice[k]].mask);\n        }\n        return u;\n    }\n\n    bool sign_consistent(const Mask &u) const {\n        for (int t = 0; t < (int)drilledCells.size(); t++) {\n            int idx = drilledCells[t];\n            bool pos = mask_test(u, idx);\n            if ((drilledObs[t] > 0) != pos) return false;\n        }\n        return true;\n    }\n\n    UnionSummary summarize_unions() {\n        UnionSummary us;\n\n        vector<pair<Mask,double>> items;\n        items.reserve(pool.size());\n\n        // Prefer unions consistent with drilled signs.\n        for (const auto &st : pool) {\n            Mask u = union_of_choice(st.choice);\n            if (sign_consistent(u)) {\n                us.hasPlausible = true;\n                double scalar = st.pen * 4.0 + st.div;\n                items.push_back({u, scalar});\n            }\n        }\n\n        // If none, fall back to all pool states for picking next drill.\n        if (!us.hasPlausible) {\n            for (const auto &st : pool) {\n                Mask u = union_of_choice(st.choice);\n                double scalar = st.pen * 8.0 + st.div;\n                items.push_back({u, scalar});\n            }\n        }\n\n        if (items.empty()) {\n            Mask u{};\n            mask_clear(u);\n            us.masks.push_back(u);\n            us.weights.push_back(1.0);\n            us.bestMask = u;\n            us.bestWeight = 1.0;\n            us.bestCell = 0;\n            return us;\n        }\n\n        double base = 1e100;\n        for (auto &it : items) base = min(base, it.second);\n\n        for (auto &it : items) {\n            double w = exp(-min(50.0, (it.second - base) / 2.0));\n            int pos = -1;\n            for (int i = 0; i < (int)us.masks.size(); i++) {\n                if (us.masks[i] == it.first) {\n                    pos = i;\n                    break;\n                }\n            }\n            if (pos == -1) {\n                us.masks.push_back(it.first);\n                us.weights.push_back(w);\n            } else {\n                us.weights[pos] += w;\n            }\n        }\n\n        double sumW = 0.0;\n        for (double w : us.weights) sumW += w;\n        if (sumW <= 0) {\n            sumW = (double)us.weights.size();\n            for (double &w : us.weights) w = 1.0;\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)us.weights.size(); i++) {\n            if (us.weights[i] > us.weights[bestIdx]) bestIdx = i;\n        }\n        us.bestMask = us.masks[bestIdx];\n        us.bestWeight = us.weights[bestIdx] / sumW;\n\n        vector<double> p(NN, 0.0);\n        for (int u = 0; u < (int)us.masks.size(); u++) {\n            double w = us.weights[u] / sumW;\n            for (int idx = 0; idx < NN; idx++) {\n                if (mask_test(us.masks[u], idx)) p[idx] += w;\n            }\n        }\n\n        us.maxEntropy = -1.0;\n        us.bestCell = -1;\n        for (int idx = 0; idx < NN; idx++) {\n            if (drilledFlag[idx]) continue;\n            double e = p[idx] * (1.0 - p[idx]);\n            if (e > us.maxEntropy + 1e-15) {\n                us.maxEntropy = e;\n                us.bestCell = idx;\n            }\n        }\n        if (us.maxEntropy < 1e-15) us.bestCell = -1;\n        return us;\n    }\n\n    bool should_answer(const UnionSummary &us, double wth, bool allowEntropy) {\n        if (!us.hasPlausible) return false;\n        if ((int)us.masks.size() <= 1) return true;\n        if (us.bestCell < 0) return true;\n        if (us.bestWeight >= wth) return true;\n        if (allowEntropy && (int)drilledCells.size() >= 3 && us.maxEntropy < 0.015) return true;\n        return false;\n    }\n\n    void record_drill(int idx, int val) {\n        if (!drilledFlag[idx]) {\n            drilledFlag[idx] = 1;\n            cellObs[idx] = val;\n            drilledCells.push_back(idx);\n            drilledObs.push_back(val);\n        }\n    }\n\n    void full_drill_and_answer() {\n        for (int idx = 0; idx < NN; idx++) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n        Mask ans{};\n        mask_clear(ans);\n        for (int idx = 0; idx < NN; idx++) {\n            if (cellObs[idx] > 0) mask_set(ans, idx);\n        }\n        answer_mask(ans);\n    }\n\n    void solve() {\n        stTime = chrono::steady_clock::now();\n\n        read_input();\n        build_queries();\n        precompute_placements();\n\n        // Stage 1: rows + columns\n        activate_queries(0, 2 * N);\n        optimize_pool(12, 0, 5, true);\n        {\n            auto us = summarize_unions();\n            if (should_answer(us, 0.999, false)) {\n                if (answer_mask(us.bestMask)) return;\n                full_drill_and_answer();\n                return;\n            }\n        }\n\n        // Stage 2: mod 2 classes\n        activate_queries(2 * N, 2 * N + 4);\n        optimize_pool(6, 4, 4, false);\n        {\n            auto us = summarize_unions();\n            if (should_answer(us, 0.995, false)) {\n                if (answer_mask(us.bestMask)) return;\n                full_drill_and_answer();\n                return;\n            }\n        }\n\n        // Stage 3: mod 3 classes\n        activate_queries(2 * N + 4, Qall);\n        optimize_pool(6, 5, 4, false);\n        {\n            auto us = summarize_unions();\n            if (should_answer(us, 0.985, false)) {\n                if (answer_mask(us.bestMask)) return;\n                full_drill_and_answer();\n                return;\n            }\n        }\n\n        int heuristicLimit;\n        if (M <= 4) heuristicLimit = 16;\n        else if (M <= 8) heuristicLimit = 12;\n        else heuristicLimit = 8;\n        heuristicLimit = min(heuristicLimit, NN / 4);\n\n        bool guessedWrong = false;\n\n        for (int step = 0; step < heuristicLimit; step++) {\n            if (elapsed() > 2.6) break;\n\n            auto us = summarize_unions();\n            double th = ((int)drilledCells.size() >= 3 ? 0.95 : 0.97);\n            if (should_answer(us, th, true)) {\n                if (answer_mask(us.bestMask)) return;\n                guessedWrong = true;\n                break;\n            }\n\n            int idx = us.bestCell;\n            if (idx < 0) break;\n\n            int val = ask_drill(idx);\n            record_drill(idx, val);\n\n            optimize_pool(3, 5, 3, false);\n            if (!pool.empty() && pool[0].pen > 0 && elapsed() < 2.2) {\n                optimize_pool(5, 6, 4, false);\n            }\n        }\n\n        if (!guessedWrong) {\n            auto us = summarize_unions();\n            if (should_answer(us, 0.94, true)) {\n                if (answer_mask(us.bestMask)) return;\n            }\n        }\n\n        full_drill_and_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long INF64 = (1LL << 60);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct Solution {\n    long long cost = INF64;\n    vector<vector<Rect>> rects; // [D][N]\n};\n\nint D, N;\nvector<vector<int>> a; // [D][N]\n\n// ---------- Utility ----------\n\nstatic inline int count_common_arr(const int* A, int nA, const int* B, int nB) {\n    int i = 0, j = 0, c = 0;\n    while (i < nA && j < nB) {\n        if (A[i] == B[j]) {\n            ++c; ++i; ++j;\n        } else if (A[i] < B[j]) {\n            ++i;\n        } else {\n            ++j;\n        }\n    }\n    return c;\n}\n\nstatic inline int count_common_vec(const vector<int>& A, const vector<int>& B) {\n    int i = 0, j = 0, c = 0;\n    while (i < (int)A.size() && j < (int)B.size()) {\n        if (A[i] == B[j]) {\n            ++c; ++i; ++j;\n        } else if (A[i] < B[j]) {\n            ++i;\n        } else {\n            ++j;\n        }\n    }\n    return c;\n}\n\n// ---------- Candidate 1: fixed full-width strips ----------\n\nlong long marginal_gain_all_days(int idx, int cur_h) {\n    long long gain = 0;\n    int area = W * cur_h;\n    for (int d = 0; d < D; ++d) {\n        int rem = a[d][idx] - area;\n        if (rem > 0) gain += 100LL * min(W, rem);\n    }\n    return gain;\n}\n\nvector<int> optimize_fixed_strips_all_days() {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>; // gain, idx, current_h\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) {\n        pq.emplace(marginal_gain_all_days(i, h[i]), i, h[i]);\n    }\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            // Put all useless extra height into the last strip,\n            // so earlier cut positions do not move.\n            h[N - 1] += rem;\n            rem = 0;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_all_days(idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nlong long fixed_strips_cost(const vector<int>& h) {\n    long long cost = 0;\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            int area = W * h[k];\n            if (a[d][k] > area) cost += 100LL * (a[d][k] - area);\n        }\n    }\n    return cost;\n}\n\nSolution solve_fixed_strips() {\n    Solution sol;\n    vector<int> h = optimize_fixed_strips_all_days();\n    sol.cost = fixed_strips_cost(h);\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n    return sol;\n}\n\n// ---------- Candidate 2: day-by-day full-width strips ----------\n\nlong long marginal_gain_one_day(int d, int idx, int cur_h) {\n    int area = W * cur_h;\n    int rem = a[d][idx] - area;\n    if (rem <= 0) return 0;\n    return 100LL * min(W, rem);\n}\n\nvector<int> optimize_strips_one_day(int d) {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>; // gain, idx, current_h\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) {\n        pq.emplace(marginal_gain_one_day(d, i, h[i]), i, h[i]);\n    }\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            rem = 0;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_one_day(d, idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_daily_strips() {\n    Solution sol;\n    vector<vector<int>> hs(D, vector<int>(N));\n    sol.rects.assign(D, vector<Rect>(N));\n    sol.cost = 0;\n\n    for (int d = 0; d < D; ++d) {\n        hs[d] = optimize_strips_one_day(d);\n\n        for (int k = 0; k < N; ++k) {\n            int area = W * hs[d][k];\n            if (a[d][k] > area) sol.cost += 100LL * (a[d][k] - area);\n        }\n\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + hs[d][k], W};\n            y += hs[d][k];\n        }\n    }\n\n    // transition cost\n    for (int d = 1; d < D; ++d) {\n        vector<int> prevCuts, curCuts;\n        prevCuts.reserve(N - 1);\n        curCuts.reserve(N - 1);\n\n        int s = 0;\n        for (int k = 0; k + 1 < N; ++k) {\n            s += hs[d - 1][k];\n            prevCuts.push_back(s);\n        }\n        s = 0;\n        for (int k = 0; k + 1 < N; ++k) {\n            s += hs[d][k];\n            curCuts.push_back(s);\n        }\n\n        int common = count_common_vec(prevCuts, curCuts);\n        sol.cost += 2000LL * ((N - 1) - common);\n    }\n\n    return sol;\n}\n\n// ---------- Candidate 3: fixed rows, dynamic widths in each row ----------\n\nstruct RowChoice {\n    int l, r;\n    int h;\n    int last_idx;\n    bool rev;\n};\n\nSolution solve_row_dp_zero_shortage() {\n    Solution sol;\n\n    // pref[(h,d,k)] = sum_{t<k} ceil(a[d][t] / h)\n    // h in [1..1000], d in [0..D-1], k in [0..N]\n    const int strideK = N + 1;\n    const int strideD = D * strideK;\n    vector<int> pref((W + 1) * strideD, 0);\n\n    auto idxPref = [&](int h, int d, int k) -> int {\n        return h * strideD + d * strideK + k;\n    };\n\n    for (int h = 1; h <= W; ++h) {\n        for (int d = 0; d < D; ++d) {\n            pref[idxPref(h, d, 0)] = 0;\n            for (int k = 0; k < N; ++k) {\n                pref[idxPref(h, d, k + 1)] = pref[idxPref(h, d, k)] + (a[d][k] + h - 1) / h;\n            }\n        }\n    }\n\n    const int INFH = W + 1;\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, INFH));\n    vector<vector<long long>> rowCost(N + 1, vector<long long>(N + 1, INF64));\n    vector<vector<int>> bestLast(N + 1, vector<int>(N + 1, -1));\n    vector<vector<char>> bestRev(N + 1, vector<char>(N + 1, 0));\n\n    auto interval_ok = [&](int l, int r, int h) -> bool {\n        for (int d = 0; d < D; ++d) {\n            int base = idxPref(h, d, 0);\n            int need = pref[base + r] - pref[base + l];\n            if (need > W) return false;\n        }\n        return true;\n    };\n\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            if (!interval_ok(l, r, W)) continue;\n\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (interval_ok(l, r, mid)) hi = mid;\n                else lo = mid + 1;\n            }\n            int h = lo;\n            reqH[l][r] = h;\n\n            int m = r - l;\n            if (m == 1) {\n                rowCost[l][r] = 0;\n                bestLast[l][r] = l;\n                bestRev[l][r] = 0;\n                continue;\n            }\n\n            long long bestC = INF64;\n            int bestP = l;\n            bool bestR = false;\n\n            for (int p = l; p < r; ++p) {\n                for (int rev = 0; rev <= 1; ++rev) {\n                    long long total = 0;\n                    int prevCuts[64], curCuts[64];\n                    int prevLen = 0;\n\n                    for (int d = 0; d < D; ++d) {\n                        int base = idxPref(h, d, 0);\n                        int len = 0;\n                        int s = 0;\n\n                        if (!rev) {\n                            for (int k = l; k < r; ++k) if (k != p) {\n                                int w = pref[base + k + 1] - pref[base + k];\n                                s += w;\n                                curCuts[len++] = s;\n                            }\n                        } else {\n                            for (int k = r - 1; k >= l; --k) if (k != p) {\n                                int w = pref[base + k + 1] - pref[base + k];\n                                s += w;\n                                curCuts[len++] = s;\n                            }\n                        }\n\n                        if (d > 0) {\n                            int common = count_common_arr(prevCuts, prevLen, curCuts, len);\n                            total += 2LL * h * (len - common);\n                        }\n\n                        prevLen = len;\n                        for (int i = 0; i < len; ++i) prevCuts[i] = curCuts[i];\n                    }\n\n                    if (total < bestC) {\n                        bestC = total;\n                        bestP = p;\n                        bestR = (bool)rev;\n                    }\n                }\n            }\n\n            rowCost[l][r] = bestC;\n            bestLast[l][r] = bestP;\n            bestRev[l][r] = (char)bestR;\n        }\n    }\n\n    // DP over prefix of reservations and used total height\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, INF64));\n    vector<vector<short>> prvI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> prvH(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] >= INF64) continue;\n            for (int j = i + 1; j <= N; ++j) {\n                int h = reqH[i][j];\n                if (h > W) continue;\n                if (used + h > W) continue;\n                long long ndp = dp[i][used] + rowCost[i][j];\n                if (ndp < dp[j][used + h]) {\n                    dp[j][used + h] = ndp;\n                    prvI[j][used + h] = (short)i;\n                    prvH[j][used + h] = (short)used;\n                }\n            }\n        }\n    }\n\n    int bestUsed = -1;\n    long long bestTotal = INF64;\n    for (int used = 0; used <= W; ++used) {\n        if (dp[N][used] < bestTotal) {\n            bestTotal = dp[N][used];\n            bestUsed = used;\n        }\n    }\n\n    if (bestUsed < 0 || bestTotal >= INF64) {\n        return sol; // infeasible in this model\n    }\n\n    vector<RowChoice> rows;\n    {\n        int ci = N, ch = bestUsed;\n        while (ci > 0) {\n            int pi = prvI[ci][ch];\n            int ph = prvH[ci][ch];\n            RowChoice rc;\n            rc.l = pi;\n            rc.r = ci;\n            rc.h = reqH[pi][ci];\n            rc.last_idx = bestLast[pi][ci];\n            rc.rev = bestRev[pi][ci];\n            rows.push_back(rc);\n            ci = pi;\n            ch = ph;\n        }\n        reverse(rows.begin(), rows.end());\n    }\n\n    sol.cost = bestTotal;\n    sol.rects.assign(D, vector<Rect>(N));\n\n    int y = 0;\n    for (const auto& row : rows) {\n        int l = row.l, r = row.r, h = row.h, p = row.last_idx;\n        bool rev = row.rev;\n\n        for (int d = 0; d < D; ++d) {\n            int x = 0;\n            int base = idxPref(h, d, 0);\n\n            if (!rev) {\n                for (int k = l; k < r; ++k) if (k != p) {\n                    int w = pref[base + k + 1] - pref[base + k];\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            } else {\n                for (int k = r - 1; k >= l; --k) if (k != p) {\n                    int w = pref[base + k + 1] - pref[base + k];\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            }\n\n            sol.rects[d][p] = {y, x, y + h, W};\n        }\n\n        y += h;\n    }\n\n    return sol;\n}\n\n// ---------- Main ----------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\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    Solution best = solve_fixed_strips();\n\n    {\n        Solution s = solve_daily_strips();\n        if (s.cost < best.cost) best = std::move(s);\n    }\n    {\n        Solution s = solve_row_dp_zero_shortage();\n        if (s.cost < best.cost) best = std::move(s);\n    }\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            const auto& r = best.rects[d][k];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing i64 = long long;\nusing u32 = uint32_t;\n\nstatic constexpr u32 MOD = 998244353;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 0) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nstruct Op {\n    uint8_t m, p, q;\n    array<uint8_t, 9> idx;\n    array<u32, 9> val;\n};\n\nstruct Solution {\n    array<u32, 81> board{};\n    i64 score = 0;\n    vector<int> used; // list of operation ids; order is irrelevant\n};\n\nstruct Move1 {\n    i64 gain = 0;\n    int type = 0; // 0 none, 1 add, 2 remove, 3 replace\n    int pos = -1;\n    int op = -1;\n};\n\nstruct PairMove {\n    i64 gain = 0;\n    int op1 = -1, op2 = -1;\n};\n\nclass Solver {\npublic:\n    int N, M, K;\n    array<u32, 81> init_board{};\n    i64 init_score = 0;\n    vector<array<array<u32, 3>, 3>> stamps;\n    vector<Op> ops;\n\n    Timer timer;\n    SplitMix64 rng;\n    double END_TIME = 1.88;\n\n    Solver(int N_, int M_, int K_) : N(N_), M(M_), K(K_) {\n        stamps.resize(M);\n    }\n\n    void read_input() {\n        uint64_t seed = 0x123456789abcdef0ULL;\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            for (int j = 0; j < N; j++) {\n                u32 x;\n                cin >> x;\n                init_board[i * N + j] = x;\n                init_score += x;\n                mix_seed(x + 1000003ULL * (i * N + j + 1));\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                    u32 x;\n                    cin >> x;\n                    stamps[m][i][j] = x;\n                    mix_seed(x + 10007ULL * (m + 1) + 1009ULL * i + j);\n                }\n            }\n        }\n\n        rng = SplitMix64(seed);\n        build_ops();\n    }\n\n    void build_ops() {\n        ops.clear();\n        ops.reserve(M * (N - 2) * (N - 2));\n        for (int m = 0; m < M; m++) {\n            for (int p = 0; p <= N - 3; p++) {\n                for (int q = 0; q <= N - 3; q++) {\n                    Op op;\n                    op.m = (uint8_t)m;\n                    op.p = (uint8_t)p;\n                    op.q = (uint8_t)q;\n                    int t = 0;\n                    for (int i = 0; i < 3; i++) {\n                        for (int j = 0; j < 3; j++) {\n                            op.idx[t] = (uint8_t)((p + i) * N + (q + j));\n                            op.val[t] = stamps[m][i][j];\n                            t++;\n                        }\n                    }\n                    ops.push_back(op);\n                }\n            }\n        }\n    }\n\n    inline i64 gain_add(const array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) {\n            u32 x = board[op.idx[k]];\n            u32 s = op.val[k];\n            u32 y = x + s;\n            if (y >= MOD) {\n                g += (i64)y - MOD - x;\n            } else {\n                g += (i64)s;\n            }\n        }\n        return g;\n    }\n\n    inline i64 gain_remove(const array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) {\n            u32 x = board[op.idx[k]];\n            u32 s = op.val[k];\n            if (x >= s) {\n                g -= (i64)s;\n            } else {\n                g += (i64)MOD - s;\n            }\n        }\n        return g;\n    }\n\n    inline void apply_add_board(array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        for (int k = 0; k < 9; k++) {\n            u32& x = board[op.idx[k]];\n            x += op.val[k];\n            if (x >= MOD) x -= MOD;\n        }\n    }\n\n    inline void apply_remove_board(array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        for (int k = 0; k < 9; k++) {\n            u32& x = board[op.idx[k]];\n            u32 s = op.val[k];\n            if (x >= s) x -= s;\n            else x = x + MOD - s;\n        }\n    }\n\n    inline void add_op(Solution& sol, int opid) const {\n        i64 g = gain_add(sol.board, opid);\n        sol.score += g;\n        apply_add_board(sol.board, opid);\n        sol.used.push_back(opid);\n    }\n\n    inline void remove_at(Solution& sol, int pos) const {\n        int opid = sol.used[pos];\n        i64 g = gain_remove(sol.board, opid);\n        sol.score += g;\n        apply_remove_board(sol.board, opid);\n        sol.used[pos] = sol.used.back();\n        sol.used.pop_back();\n    }\n\n    inline void replace_at(Solution& sol, int pos, int new_opid) const {\n        int old_opid = sol.used[pos];\n        sol.score += gain_remove(sol.board, old_opid);\n        apply_remove_board(sol.board, old_opid);\n        sol.score += gain_add(sol.board, new_opid);\n        apply_add_board(sol.board, new_opid);\n        sol.used[pos] = new_opid;\n    }\n\n    Solution make_empty_solution() const {\n        Solution s;\n        s.board = init_board;\n        s.score = init_score;\n        s.used.reserve(K);\n        return s;\n    }\n\n    int find_best_add(const array<u32, 81>& board, i64& best_gain) const {\n        best_gain = 0;\n        int best_id = -1;\n        const int O = (int)ops.size();\n        for (int opid = 0; opid < O; opid++) {\n            i64 g = gain_add(board, opid);\n            if (g > best_gain) {\n                best_gain = g;\n                best_id = opid;\n            }\n        }\n        return best_id;\n    }\n\n    int find_best_remove(const Solution& sol, i64& best_gain) const {\n        best_gain = 0;\n        int best_pos = -1;\n        for (int i = 0; i < (int)sol.used.size(); i++) {\n            i64 g = gain_remove(sol.board, sol.used[i]);\n            if (g > best_gain) {\n                best_gain = g;\n                best_pos = i;\n            }\n        }\n        return best_pos;\n    }\n\n    Move1 find_best_move1(const Solution& sol) const {\n        Move1 mv;\n\n        if ((int)sol.used.size() < K) {\n            i64 g_add;\n            int opid = find_best_add(sol.board, g_add);\n            if (g_add > mv.gain) {\n                mv.gain = g_add;\n                mv.type = 1;\n                mv.op = opid;\n            }\n        }\n\n        if (!sol.used.empty()) {\n            i64 g_rem;\n            int pos = find_best_remove(sol, g_rem);\n            if (g_rem > mv.gain) {\n                mv.gain = g_rem;\n                mv.type = 2;\n                mv.pos = pos;\n            }\n\n            // best replace = remove one selected op, then add the best single op\n            array<u32, 81> tmp;\n            for (int i = 0; i < (int)sol.used.size(); i++) {\n                tmp = sol.board;\n                int old_op = sol.used[i];\n                i64 g1 = gain_remove(tmp, old_op);\n                apply_remove_board(tmp, old_op);\n\n                i64 g2;\n                int new_op = find_best_add(tmp, g2);\n                i64 g = g1 + g2;\n                if (new_op != -1 && g > mv.gain) {\n                    mv.gain = g;\n                    mv.type = 3;\n                    mv.pos = i;\n                    mv.op = new_op;\n                }\n            }\n        }\n\n        return mv;\n    }\n\n    PairMove find_best_pair_add(const array<u32, 81>& board) const {\n        PairMove best;\n        const int O = (int)ops.size();\n        array<u32, 81> tmp;\n\n        for (int i = 0; i < O; i++) {\n            tmp = board;\n            i64 g1 = gain_add(tmp, i);\n            apply_add_board(tmp, i);\n\n            for (int j = i; j < O; j++) {\n                i64 g = g1 + gain_add(tmp, j);\n                if (g > best.gain) {\n                    best.gain = g;\n                    best.op1 = i;\n                    best.op2 = j;\n                }\n            }\n        }\n        return best;\n    }\n\n    void hill_climb(Solution& sol) {\n        while (timer.elapsed() < END_TIME) {\n            Move1 mv = find_best_move1(sol);\n\n            if (mv.gain > 0) {\n                if (mv.type == 1) {\n                    add_op(sol, mv.op);\n                } else if (mv.type == 2) {\n                    remove_at(sol, mv.pos);\n                } else if (mv.type == 3) {\n                    replace_at(sol, mv.pos, mv.op);\n                }\n                continue;\n            }\n\n            // Larger neighborhood: add 2 operations together if no 1-move improves.\n            if ((int)sol.used.size() + 2 <= K && timer.elapsed() < END_TIME - 0.02) {\n                PairMove pm = find_best_pair_add(sol.board);\n                if (pm.gain > 0) {\n                    add_op(sol, pm.op1);\n                    add_op(sol, pm.op2);\n                    continue;\n                }\n            }\n\n            break;\n        }\n    }\n\n    static bool cmp_pair_desc(const pair<i64, int>& a, const pair<i64, int>& b) {\n        return a.first > b.first;\n    }\n\n    int choose_rank(int cnt) {\n        int r = 0;\n        while (r + 1 < cnt && rng.next_int(100) < 30) r++;\n        return r;\n    }\n\n    Solution random_construct() {\n        Solution sol = make_empty_solution();\n        const int O = (int)ops.size();\n        const int TOP = 12;\n        vector<pair<i64, int>> cand;\n        cand.reserve(O);\n\n        while ((int)sol.used.size() < K && timer.elapsed() < END_TIME) {\n            cand.clear();\n            for (int opid = 0; opid < O; opid++) {\n                i64 g = gain_add(sol.board, opid);\n                if (g > 0) cand.push_back({g, opid});\n            }\n            if (cand.empty()) break;\n\n            int take = min(TOP, (int)cand.size());\n            nth_element(cand.begin(), cand.begin() + take - 1, cand.end(), cmp_pair_desc);\n            cand.resize(take);\n            sort(cand.begin(), cand.end(), cmp_pair_desc);\n\n            int rank = choose_rank((int)cand.size());\n            add_op(sol, cand[rank].second);\n        }\n\n        return sol;\n    }\n\n    Solution perturb(const Solution& base) {\n        Solution sol = base;\n\n        if (!sol.used.empty()) {\n            int L = (int)sol.used.size();\n            int d;\n            if (rng.next_int(100) < 20) d = 1 + rng.next_int(min(L, 10));\n            else d = 1 + rng.next_int(min(L, 4));\n\n            for (int t = 0; t < d && !sol.used.empty(); t++) {\n                int pos = rng.next_int((int)sol.used.size());\n                remove_at(sol, pos);\n            }\n        }\n\n        // A few random greedy adds to diversify before hill-climbing\n        const int O = (int)ops.size();\n        const int TOP = 6;\n        vector<pair<i64, int>> cand;\n        cand.reserve(O);\n\n        int extra = rng.next_int(4);\n        for (int step = 0; step < extra && (int)sol.used.size() < K && timer.elapsed() < END_TIME; step++) {\n            cand.clear();\n            for (int opid = 0; opid < O; opid++) {\n                i64 g = gain_add(sol.board, opid);\n                if (g > 0) cand.push_back({g, opid});\n            }\n            if (cand.empty()) break;\n\n            int take = min(TOP, (int)cand.size());\n            nth_element(cand.begin(), cand.begin() + take - 1, cand.end(), cmp_pair_desc);\n            cand.resize(take);\n            sort(cand.begin(), cand.end(), cmp_pair_desc);\n\n            int rank = rng.next_int((int)cand.size());\n            add_op(sol, cand[rank].second);\n        }\n\n        return sol;\n    }\n\n    Solution solve() {\n        // Initial deterministic greedy\n        Solution best = make_empty_solution();\n        while ((int)best.used.size() < K && timer.elapsed() < END_TIME) {\n            i64 g;\n            int opid = find_best_add(best.board, g);\n            if (g <= 0) break;\n            add_op(best, opid);\n        }\n        hill_climb(best);\n\n        int iter = 0;\n        while (timer.elapsed() < END_TIME - 0.02) {\n            Solution cur;\n            if (iter < 3 || rng.next_int(100) < 30) {\n                cur = random_construct();\n            } else {\n                cur = perturb(best);\n            }\n            hill_climb(cur);\n            if (cur.score > best.score) {\n                best = std::move(cur);\n            }\n            iter++;\n        }\n\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K;\n\n    Solver solver(N, M, K);\n    solver.read_input();\n    Solution ans = solver.solve();\n\n    cout << ans.used.size() << '\\n';\n    for (int opid : ans.used) {\n        const Op& op = solver.ops[opid];\n        cout << (int)op.m << ' ' << (int)op.p << ' ' << (int)op.q << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int CNUM = N * N;\n\nstruct Solver {\n    int A[N][N];\n\n    int src_of[CNUM];\n    int pos_of[CNUM];\n\n    // Planner state\n    int idx[N];                 // number of containers already taken from each source\n    bool done[CNUM];            // already dispatched\n    int need[N];                // smallest not-yet-dispatched label in each destination row\n    int loc_type[CNUM];         // 0: still in source/hidden, 1: buffered, 2: dispatched\n    pair<int,int> buf_pos[CNUM];\n    int buffer_occ[N][N];       // -1 if no buffered container on that cell\n\n    int done_cnt = 0;\n\n    // Simulator state\n    struct Crane {\n        bool alive = true;\n        int r = 0, c = 0;\n        int hold = -1;\n        bool large = false;\n    };\n    Crane cranes[N];\n    int cont[N][N];             // container on grid cell, -1 if none\n    int arrival_idx[N];         // next to appear at each source gate\n\n    vector<string> out;\n    int T = 0;\n\n    Solver() {\n        memset(src_of, -1, sizeof(src_of));\n        memset(pos_of, -1, sizeof(pos_of));\n        memset(idx, 0, sizeof(idx));\n        memset(done, 0, sizeof(done));\n        memset(loc_type, 0, sizeof(loc_type));\n        memset(buffer_occ, -1, sizeof(buffer_occ));\n        memset(cont, -1, sizeof(cont));\n        memset(arrival_idx, 0, sizeof(arrival_idx));\n        out.assign(N, \"\");\n    }\n\n    static int mdist(pair<int,int> a, pair<int,int> b) {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    pair<int,int> cur_pos() const {\n        return {cranes[0].r, cranes[0].c};\n    }\n\n    void update_need(int d) {\n        while (need[d] <= 5 * d + 4 && done[need[d]]) need[d]++;\n    }\n\n    bool is_move(char ch) const {\n        return ch == 'U' || ch == 'D' || ch == 'L' || ch == 'R';\n    }\n\n    void step_sim(const string &act) {\n        // 1. arrivals\n        for (int r = 0; r < N; r++) {\n            if (arrival_idx[r] >= N) continue;\n            if (cont[r][0] != -1) continue;\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (!blocked) {\n                cont[r][0] = A[r][arrival_idx[r]];\n                arrival_idx[r]++;\n            }\n        }\n\n        array<pair<int,int>, N> oldp, newp;\n        for (int i = 0; i < N; i++) {\n            oldp[i] = {cranes[i].r, cranes[i].c};\n            newp[i] = oldp[i];\n        }\n\n        // movement destination\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            char a = act[i];\n            int nr = cranes[i].r, nc = cranes[i].c;\n            if (a == 'U') nr--;\n            if (a == 'D') nr++;\n            if (a == 'L') nc--;\n            if (a == 'R') nc++;\n            if (is_move(a)) {\n                nr = max(0, min(N - 1, nr));\n                nc = max(0, min(N - 1, nc));\n                // small crane with container cannot move onto occupied container cell\n                if (!cranes[i].large && cranes[i].hold != -1) {\n                    if (cont[nr][nc] != -1) {\n                        // never happens in our output\n                    }\n                }\n                newp[i] = {nr, nc};\n            }\n        }\n\n        // collisions / passing\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            for (int j = i + 1; j < N; j++) {\n                if (!cranes[j].alive) continue;\n\n                bool bi = (act[i] == 'B');\n                bool bj = (act[j] == 'B');\n\n                if (!bi && !bj) {\n                    if (newp[i] == newp[j]) {\n                        // never happens in our output\n                    }\n                    bool mi = (newp[i] != oldp[i]);\n                    bool mj = (newp[j] != oldp[j]);\n                    if (mi && mj && newp[i] == oldp[j] && newp[j] == oldp[i]) {\n                        // never happens in our output\n                    }\n                }\n            }\n        }\n\n        // bombs\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            if (act[i] == 'B') {\n                if (cranes[i].hold == -1) cranes[i].alive = false;\n            }\n        }\n\n        // moves\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            if (is_move(act[i])) {\n                cranes[i].r = newp[i].first;\n                cranes[i].c = newp[i].second;\n            }\n        }\n\n        // pick / drop\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n            if (a == 'P') {\n                if (cranes[i].hold == -1 && cont[r][c] != -1) {\n                    cranes[i].hold = cont[r][c];\n                    cont[r][c] = -1;\n                }\n            } else if (a == 'Q') {\n                if (cranes[i].hold != -1 && cont[r][c] == -1) {\n                    cont[r][c] = cranes[i].hold;\n                    cranes[i].hold = -1;\n                }\n            }\n        }\n\n        // 3. dispatch\n        for (int r = 0; r < N; r++) {\n            if (cont[r][N - 1] != -1) {\n                cont[r][N - 1] = -1;\n            }\n        }\n    }\n\n    void emit(char a0) {\n        string act(N, '.');\n        act[0] = a0;\n        if (T == 0) {\n            for (int i = 1; i < N; i++) act[i] = 'B';\n        }\n        for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n        step_sim(act);\n        T++;\n    }\n\n    void move_to(int tr, int tc) {\n        while (cranes[0].r < tr) emit('D');\n        while (cranes[0].r > tr) emit('U');\n        while (cranes[0].c < tc) emit('R');\n        while (cranes[0].c > tc) emit('L');\n    }\n\n    bool ready_id(int id) const {\n        if (id < 0 || id >= CNUM) return false;\n        if (done[id]) return false;\n        if (loc_type[id] == 1) return true;\n        int s = src_of[id];\n        return pos_of[id] == idx[s];\n    }\n\n    vector<pair<int,int>> free_slots() const {\n        vector<pair<int,int>> ret;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 3; c++) {\n                if (buffer_occ[r][c] == -1) ret.push_back({r, c});\n            }\n        }\n        for (int r = 0; r < N; r++) {\n            if (idx[r] == N && buffer_occ[r][0] == -1) {\n                ret.push_back({r, 0});\n            }\n        }\n        return ret;\n    }\n\n    pair<int,int> choose_slot(int src_row, int dest_row) const {\n        auto slots = free_slots();\n        pair<int,int> best = {-1, -1};\n        int best_total = 1e9;\n        int best_pref = -1;\n        int best_now = 1e9;\n\n        for (auto [r, c] : slots) {\n            int total = abs(src_row - r) + abs(r - dest_row);\n            int pref = (r == dest_row) ? 1 : 0;\n            int now = abs(src_row - r) + c;\n            if (total < best_total ||\n                (total == best_total && pref > best_pref) ||\n                (total == best_total && pref == best_pref && now < best_now) ||\n                (total == best_total && pref == best_pref && now == best_now && make_pair(r,c) < best)) {\n                best_total = total;\n                best_pref = pref;\n                best_now = now;\n                best = {r, c};\n            }\n        }\n        return best;\n    }\n\n    int choose_ready() const {\n        int best_id = -1;\n        int best_cost = 1e9;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > 5 * d + 4) continue;\n            if (!ready_id(t)) continue;\n\n            pair<int,int> loc;\n            if (loc_type[t] == 1) loc = buf_pos[t];\n            else loc = {src_of[t], 0};\n\n            int cost = mdist(cp, loc) + abs(loc.first - d) + (4 - loc.second);\n            if (cost < best_cost || (cost == best_cost && t < best_id)) {\n                best_cost = cost;\n                best_id = t;\n            }\n        }\n        return best_id;\n    }\n\n    int choose_target_row() const {\n        int best_d = -1;\n        int best_depth = 1e9;\n        int best_front = 1e9;\n        int best_travel = 1e9;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > 5 * d + 4) continue;\n            if (ready_id(t)) continue;\n\n            int s = src_of[t];\n            int depth = pos_of[t] - idx[s];\n            int front = A[s][idx[s]];\n            int travel = abs(cp.first - s) + cp.second; // to (s,0)\n\n            if (depth < best_depth ||\n                (depth == best_depth && front < best_front) ||\n                (depth == best_depth && front == best_front && travel < best_travel) ||\n                (depth == best_depth && front == best_front && travel == best_travel && d < best_d)) {\n                best_depth = depth;\n                best_front = front;\n                best_travel = travel;\n                best_d = d;\n            }\n        }\n        return best_d;\n    }\n\n    void dispatch_id(int id) {\n        if (loc_type[id] == 1) {\n            auto [r, c] = buf_pos[id];\n            move_to(r, c);\n            emit('P');\n            buffer_occ[r][c] = -1;\n            loc_type[id] = 0; // temporary\n        } else {\n            int s = src_of[id];\n            move_to(s, 0);\n            emit('P');\n            idx[s]++;\n        }\n\n        int d = id / 5;\n        move_to(d, 4);\n        emit('Q');\n\n        done[id] = true;\n        loc_type[id] = 2;\n        done_cnt++;\n        update_need(d);\n    }\n\n    void buffer_or_dispatch_front(int s) {\n        int x = A[s][idx[s]];\n        move_to(s, 0);\n        emit('P');\n        idx[s]++;\n\n        int d = x / 5;\n        auto slot = choose_slot(s, d);\n\n        if (slot.first == -1) {\n            // fallback: dispatch directly to correct gate (may create inversions)\n            move_to(d, 4);\n            emit('Q');\n            done[x] = true;\n            loc_type[x] = 2;\n            done_cnt++;\n            update_need(d);\n        } else {\n            move_to(slot.first, slot.second);\n            emit('Q');\n            loc_type[x] = 1;\n            buf_pos[x] = slot;\n            buffer_occ[slot.first][slot.second] = x;\n        }\n    }\n\n    void solve() {\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int x = A[r][j];\n                src_of[x] = r;\n                pos_of[x] = j;\n            }\n        }\n\n        for (int d = 0; d < N; d++) need[d] = 5 * d;\n\n        for (int i = 0; i < N; i++) {\n            cranes[i].alive = true;\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].hold = -1;\n            cranes[i].large = (i == 0);\n        }\n\n        while (done_cnt < CNUM && T < 10000) {\n            int rdy = choose_ready();\n            if (rdy != -1) {\n                dispatch_id(rdy);\n                continue;\n            }\n\n            int d = choose_target_row();\n            if (d == -1) break; // should not happen\n\n            int t = need[d];\n            int s = src_of[t];\n            buffer_or_dispatch_front(s);\n        }\n\n        // Safety fallback: if anything remains, dispatch all visible/buffered/arbitrary in a simple way.\n        // In practice the main loop should finish.\n        while (done_cnt < CNUM && T < 10000) {\n            int rdy = choose_ready();\n            if (rdy != -1) {\n                dispatch_id(rdy);\n                continue;\n            }\n\n            bool progressed = false;\n            for (int s = 0; s < N && !progressed; s++) {\n                if (idx[s] >= N) continue;\n                int x = A[s][idx[s]];\n                move_to(s, 0);\n                emit('P');\n                idx[s]++;\n                int d2 = x / 5;\n                move_to(d2, 4);\n                emit('Q');\n                done[x] = true;\n                loc_type[x] = 2;\n                done_cnt++;\n                update_need(d2);\n                progressed = true;\n            }\n            if (progressed) continue;\n\n            for (int x = 0; x < CNUM && !progressed; x++) {\n                if (loc_type[x] != 1) continue;\n                auto [r, c] = buf_pos[x];\n                move_to(r, c);\n                emit('P');\n                buffer_occ[r][c] = -1;\n                int d2 = x / 5;\n                move_to(d2, 4);\n                emit('Q');\n                done[x] = true;\n                loc_type[x] = 2;\n                done_cnt++;\n                update_need(d2);\n                progressed = true;\n            }\n            if (!progressed) break;\n        }\n\n        if (out[0].empty()) {\n            // Just in case; normally unreachable.\n            out[0] = \".\";\n            for (int i = 1; i < N; i++) out[i] = \"B\";\n        }\n\n        for (int i = 0; i < N; i++) {\n            cout << out[i] << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n; // always 5\n    Solver solver;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> solver.A[i][j];\n        }\n    }\n    solver.solve();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int r, c;\n};\n\nstatic inline int manhattan0(const Point& p) {\n    return p.r + p.c; // from (0,0)\n}\n\nPoint apply_sym(Point p, int sym, int N) {\n    // D4 group: if sym>=4, reflect by vertical axis first, then rotate.\n    if (sym >= 4) {\n        p.c = N - 1 - p.c;\n        sym -= 4;\n    }\n    for (int k = 0; k < sym; k++) {\n        int nr = p.c;\n        int nc = N - 1 - p.r;\n        p.r = nr;\n        p.c = nc;\n    }\n    return p;\n}\n\nvector<Point> make_base_cycle(int N) {\n    // Hamiltonian cycle for even N:\n    // down first column,\n    // snake columns 1..N-1 through rows 1..N-1,\n    // then top row back to (0,0).\n    vector<Point> cyc;\n    cyc.reserve(N * N);\n\n    for (int r = 0; r < N; r++) cyc.push_back({r, 0});\n\n    for (int c = 1; c < N; c++) {\n        if (c % 2 == 1) {\n            for (int r = N - 1; r >= 1; r--) cyc.push_back({r, c});\n        } else {\n            for (int r = 1; r < N; r++) cyc.push_back({r, c});\n        }\n    }\n\n    cyc.push_back({0, N - 1});\n    for (int c = N - 2; c >= 1; c--) cyc.push_back({0, c});\n\n    return cyc;\n}\n\nstring dir_between(const Point& a, const Point& b) {\n    if (b.r == a.r + 1 && b.c == a.c) return \"D\";\n    if (b.r == a.r - 1 && b.c == a.c) return \"U\";\n    if (b.r == a.r && b.c == a.c + 1) return \"R\";\n    if (b.r == a.r && b.c == a.c - 1) return \"L\";\n    return \"?\";\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> h(N, vector<int>(N));\n    long long base = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> h[i][j];\n            base += llabs(h[i][j]);\n        }\n    }\n\n    vector<Point> base_cycle = make_base_cycle(N);\n    const int M = N * N;\n\n    long long best_cost = (1LL << 62);\n    vector<Point> best_seq;\n\n    for (int sym = 0; sym < 8; sym++) {\n        vector<Point> cyc(M);\n        for (int i = 0; i < M; i++) cyc[i] = apply_sym(base_cycle[i], sym, N);\n\n        for (int rev = 0; rev < 2; rev++) {\n            vector<Point> order = cyc;\n            if (rev) reverse(order.begin(), order.end());\n\n            vector<int> a(M);\n            for (int i = 0; i < M; i++) a[i] = h[order[i].r][order[i].c];\n\n            for (int st = 0; st < M; st++) {\n                long long cur = 0;\n                long long carry_move_cost = 0;\n                bool ok = true;\n\n                for (int k = 0; k < M; k++) {\n                    cur += a[(st + k) % M];\n                    if (cur < 0) {\n                        ok = false;\n                        break;\n                    }\n                    if (k + 1 < M) carry_move_cost += cur;\n                }\n                if (!ok || cur != 0) continue;\n\n                long long total_cost =\n                    base +\n                    carry_move_cost +\n                    100LL * (M - 1 + manhattan0(order[st]));\n\n                if (total_cost < best_cost) {\n                    best_cost = total_cost;\n                    best_seq.clear();\n                    best_seq.reserve(M);\n                    for (int k = 0; k < M; k++) {\n                        best_seq.push_back(order[(st + k) % M]);\n                    }\n                }\n            }\n        }\n    }\n\n    vector<string> ans;\n    ans.reserve(2000);\n\n    Point cur_pos{0, 0};\n\n    // Initial empty move to start.\n    Point start = best_seq[0];\n    while (cur_pos.r < start.r) {\n        ans.push_back(\"D\");\n        cur_pos.r++;\n    }\n    while (cur_pos.r > start.r) {\n        ans.push_back(\"U\");\n        cur_pos.r--;\n    }\n    while (cur_pos.c < start.c) {\n        ans.push_back(\"R\");\n        cur_pos.c++;\n    }\n    while (cur_pos.c > start.c) {\n        ans.push_back(\"L\");\n        cur_pos.c--;\n    }\n\n    long long load = 0;\n\n    for (int i = 0; i < M; i++) {\n        Point p = best_seq[i];\n        int v = h[p.r][p.c];\n\n        if (v > 0) {\n            ans.push_back(\"+\" + to_string(v));\n            load += v;\n        } else if (v < 0) {\n            ans.push_back(\"-\" + to_string(-v));\n            load += v; // v is negative\n        }\n\n        if (i + 1 < M) {\n            Point q = best_seq[i + 1];\n            ans.push_back(dir_between(p, q));\n        }\n    }\n\n    for (auto &s : ans) {\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Seed {\n    array<int, 15> x{};\n    int value = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, T;\n    int S, P; // seed count, position count\n\n    vector<Seed> seeds;\n    vector<vector<int>> adj;\n    vector<pair<int, int>> edges;\n    vector<int> deg;\n    vector<int> posOrder;\n    vector<int> blackPos, whitePos;\n\n    vector<vector<int>> pairScore; // scaled by 100\n    vector<long long> ind;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, int T_)\n        : N(N_), M(M_), T(T_), S(2 * N_ * (N_ - 1)), P(N_ * N_),\n          rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        buildGrid();\n    }\n\n    void buildGrid() {\n        adj.assign(P, {});\n        deg.assign(P, 0);\n        edges.clear();\n        blackPos.clear();\n        whitePos.clear();\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                if (((r + c) & 1) == 0) blackPos.push_back(p);\n                else whitePos.push_back(p);\n\n                if (c + 1 < N) {\n                    int q = r * N + (c + 1);\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n                if (r + 1 < N) {\n                    int q = (r + 1) * N + c;\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n            }\n        }\n        for (int p = 0; p < P; p++) deg[p] = (int)adj[p].size();\n\n        vector<pair<array<int, 5>, int>> ord;\n        ord.reserve(P);\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                int dist = abs(2 * r - (N - 1)) + abs(2 * c - (N - 1));\n                ord.push_back({{dist, -deg[p], ((r + c) & 1), r, c}, p});\n            }\n        }\n        sort(ord.begin(), ord.end());\n        posOrder.clear();\n        for (auto &e : ord) posOrder.push_back(e.second);\n    }\n\n    bool readSeeds() {\n        seeds.assign(S, Seed());\n        for (int i = 0; i < S; i++) {\n            int sum = 0;\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> seeds[i].x[j])) return false;\n                sum += seeds[i].x[j];\n            }\n            seeds[i].value = sum;\n        }\n        return true;\n    }\n\n    void computePairScore(int remTurns) {\n        pairScore.assign(S, vector<int>(S, 0));\n\n        double denom = max(1, T - 1);\n        double alpha = 0.20 + 0.65 * (double)(remTurns - 1) / denom;  // early: optimistic, late: realistic\n        double beta  = 1.40 + 0.40 * (double)(T - remTurns) / denom;  // late turns care more about tail\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double mean = 0.5 * (seeds[i].value + seeds[j].value);\n                double optimistic = 0.0;\n                double diff2 = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    optimistic += max(a, b);\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n                }\n\n                double sigma = 0.5 * sqrt(diff2);\n                double realistic = min(optimistic, mean + beta * sigma);\n                double sc = alpha * optimistic + (1.0 - alpha) * realistic;\n\n                int v = (int)llround(sc * 100.0);\n                pairScore[i][j] = pairScore[j][i] = v;\n            }\n        }\n    }\n\n    void computeIndividualPotential() {\n        ind.assign(S, 0);\n        int K = min(4, S - 1);\n        vector<int> tmp;\n        tmp.reserve(S - 1);\n\n        for (int i = 0; i < S; i++) {\n            tmp.clear();\n            for (int j = 0; j < S; j++) {\n                if (i == j) continue;\n                tmp.push_back(pairScore[i][j]);\n            }\n            if (K < (int)tmp.size()) {\n                nth_element(tmp.begin(), tmp.begin() + K, tmp.end(), greater<int>());\n            }\n            long long sumTop = 0;\n            for (int k = 0; k < K; k++) sumTop += tmp[k];\n\n            // top-4 pairability + some direct value\n            ind[i] = sumTop / K + 50LL * seeds[i].value;\n        }\n    }\n\n    vector<int> initAssignment(int type, int noiseScale) {\n        vector<int> assign(P, -1);\n        vector<char> used(S, false);\n\n        if (type == 1 || type == 2) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n\n            if (type == 1) {\n                sort(ids.begin(), ids.end(), [&](int a, int b) {\n                    if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                    return ind[a] > ind[b];\n                });\n            } else {\n                sort(ids.begin(), ids.end(), [&](int a, int b) {\n                    if (ind[a] != ind[b]) return ind[a] > ind[b];\n                    return seeds[a].value > seeds[b].value;\n                });\n            }\n\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        // greedy\n        for (int p : posOrder) {\n            int fixedCnt = 0;\n            for (int nb : adj[p]) if (assign[nb] != -1) fixedCnt++;\n\n            long long bestSc = LLONG_MIN;\n            int bestSeed = -1;\n\n            for (int s = 0; s < S; s++) if (!used[s]) {\n                long long sc = 1LL * (deg[p] - fixedCnt) * ind[s];\n                for (int nb : adj[p]) {\n                    if (assign[nb] != -1) sc += pairScore[s][assign[nb]];\n                }\n                if (noiseScale > 0) sc += (long long)(rng() % (noiseScale + 1));\n\n                if (sc > bestSc || (sc == bestSc && (rng() & 1))) {\n                    bestSc = sc;\n                    bestSeed = s;\n                }\n            }\n\n            assign[p] = bestSeed;\n            used[bestSeed] = true;\n        }\n\n        return assign;\n    }\n\n    long long calcObjective(const vector<int>& assign) const {\n        long long res = 0;\n        for (auto [u, v] : edges) res += pairScore[assign[u]][assign[v]];\n        return res;\n    }\n\n    // Hungarian for maximum weight matching on n x m matrix, n <= m\n    vector<int> hungarianMax(const vector<vector<long long>>& a) const {\n        int n = (int)a.size();\n        int m = (int)a[0].size();\n        const long long INF = (1LL << 60);\n\n        vector<long long> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<long long> minv(m + 1, INF);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                long long delta = INF;\n\n                for (int j = 1; j <= m; j++) if (!used[j]) {\n                    long long cur = -a[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    void optimizeColor(vector<int>& assign, const vector<int>& group, const vector<int>& other) {\n        vector<char> banned(S, false);\n        for (int p : other) banned[assign[p]] = true;\n\n        vector<int> cand;\n        cand.reserve(S - (int)other.size());\n        for (int s = 0; s < S; s++) {\n            if (!banned[s]) cand.push_back(s);\n        }\n\n        int n = (int)group.size();\n        int m = (int)cand.size();\n        vector<vector<long long>> benefit(n, vector<long long>(m, 0));\n\n        for (int i = 0; i < n; i++) {\n            int p = group[i];\n            for (int j = 0; j < m; j++) {\n                int s = cand[j];\n                long long b = 0;\n                for (int nb : adj[p]) {\n                    b += pairScore[s][assign[nb]];\n                }\n                benefit[i][j] = b;\n            }\n        }\n\n        vector<int> choice = hungarianMax(benefit);\n        for (int i = 0; i < n; i++) {\n            assign[group[i]] = cand[choice[i]];\n        }\n    }\n\n    long long coordinateAscent(vector<int>& assign) {\n        long long obj = calcObjective(assign);\n        for (int it = 0; it < 8; it++) {\n            long long old = obj;\n            optimizeColor(assign, blackPos, whitePos);\n            optimizeColor(assign, whitePos, blackPos);\n            obj = calcObjective(assign);\n            if (obj <= old) break;\n        }\n        return obj;\n    }\n\n    long long deltaSwap(const vector<int>& assign, int p, int q) const {\n        if (p == q) return 0;\n        int a = assign[p];\n        int b = assign[q];\n        long long d = 0;\n\n        for (int nb : adj[p]) {\n            if (nb == q) continue;\n            d += (long long)pairScore[b][assign[nb]] - pairScore[a][assign[nb]];\n        }\n        for (int nb : adj[q]) {\n            if (nb == p) continue;\n            d += (long long)pairScore[a][assign[nb]] - pairScore[b][assign[nb]];\n        }\n        // edge (p,q) itself is unchanged because pairScore is symmetric\n        return d;\n    }\n\n    long long crossSwapImprove(vector<int>& assign, long long obj) {\n        for (int pass = 0; pass < 6; pass++) {\n            long long bestDelta = 0;\n            int bestB = -1, bestW = -1;\n\n            for (int p : blackPos) {\n                for (int q : whitePos) {\n                    long long d = deltaSwap(assign, p, q);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bestB = p;\n                        bestW = q;\n                    }\n                }\n            }\n\n            if (bestDelta <= 0) break;\n\n            swap(assign[bestB], assign[bestW]);\n            obj = coordinateAscent(assign);\n        }\n        return obj;\n    }\n\n    vector<int> decideLayout(int turn) {\n        int remTurns = T - turn;\n        computePairScore(remTurns);\n        computeIndividualPotential();\n\n        long long bestObj = -1;\n        vector<int> bestAssign;\n\n        int restarts = 32;\n        for (int r = 0; r < restarts; r++) {\n            int type = 0;\n            int noise = 0;\n\n            if (r == 0) {\n                type = 0; noise = 0;\n            } else if (r == 1) {\n                type = 1; noise = 0;\n            } else if (r == 2) {\n                type = 2; noise = 0;\n            } else {\n                type = 0;\n                noise = (r < 16 ? 3000 : 8000);\n            }\n\n            vector<int> assign = initAssignment(type, noise);\n            long long obj = coordinateAscent(assign);\n            obj = crossSwapImprove(assign, obj);\n\n            if (obj > bestObj) {\n                bestObj = obj;\n                bestAssign = assign;\n            }\n        }\n\n        return bestAssign;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    Solver solver(N, M, T);\n    if (!solver.readSeeds()) return 0;\n\n    for (int t = 0; t < T; t++) {\n        vector<int> assign = solver.decideLayout(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << assign[i * N + j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (!solver.readSeeds()) return 0;\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Event {\n    bool pickup; // true: source, false: target\n    int idx;\n};\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, V;\n    cin >> N >> M >> V;\n    vector<string> s(N), t(N);\n    for (int i = 0; i < N; i++) cin >> s[i];\n    for (int i = 0; i < N; i++) cin >> t[i];\n\n    // Only mismatched cells actually need moving.\n    vector<Pt> src, dst;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (s[i][j] == '1' && t[i][j] == '0') src.push_back({i, j});\n            else if (s[i][j] == '0' && t[i][j] == '1') dst.push_back({i, j});\n        }\n    }\n\n    const int Q = (int)src.size();\n    const int Vp = V;              // use all vertices\n    const int leafCount = Vp - 2;  // root(0), joint(1), leaves(2..)\n\n    // Tree output:\n    // 0 - 1 (len=1)\n    // 1 - u (len=1) for all leaves u>=2\n    auto output_tree = [&](int root_x, int root_y) {\n        cout << Vp << '\\n';\n        cout << 0 << ' ' << 1 << '\\n'; // vertex 1\n        for (int u = 2; u < Vp; u++) {\n            cout << 1 << ' ' << 1 << '\\n';\n        }\n        cout << root_x << ' ' << root_y << '\\n';\n    };\n\n    // If nothing to move, just output any valid arm and no operations.\n    if (Q == 0) {\n        output_tree(0, 0);\n        return 0;\n    }\n\n    // Precompute distance tables among mismatched cells only.\n    vector<vector<unsigned short>> SS(Q, vector<unsigned short>(Q));\n    vector<vector<unsigned short>> ST(Q, vector<unsigned short>(Q));\n    vector<vector<unsigned short>> TS(Q, vector<unsigned short>(Q));\n    vector<vector<unsigned short>> TT(Q, vector<unsigned short>(Q));\n    for (int i = 0; i < Q; i++) {\n        for (int j = 0; j < Q; j++) {\n            SS[i][j] = (unsigned short)manhattan(src[i], src[j]);\n            ST[i][j] = (unsigned short)manhattan(src[i], dst[j]);\n            TS[i][j] = (unsigned short)manhattan(dst[i], src[j]);\n            TT[i][j] = (unsigned short)manhattan(dst[i], dst[j]);\n        }\n    }\n\n    // Candidate starts. If Q is not too large, try all sources.\n    vector<int> startCandidates;\n    {\n        vector<char> used(Q, false);\n        auto add = [&](int idx) {\n            if (0 <= idx && idx < Q && !used[idx]) {\n                used[idx] = true;\n                startCandidates.push_back(idx);\n            }\n        };\n\n        const int ALL_START_THRESHOLD = 200;\n        if (Q <= ALL_START_THRESHOLD) {\n            for (int i = 0; i < Q; i++) add(i);\n        } else {\n            int minX = 0, maxX = 0, minY = 0, maxY = 0;\n            int minS = 0, maxS = 0, minD = 0, maxD = 0; // x+y, x-y\n            for (int i = 1; i < Q; i++) {\n                if (src[i].x < src[minX].x) minX = i;\n                if (src[i].x > src[maxX].x) maxX = i;\n                if (src[i].y < src[minY].y) minY = i;\n                if (src[i].y > src[maxY].y) maxY = i;\n                if (src[i].x + src[i].y < src[minS].x + src[minS].y) minS = i;\n                if (src[i].x + src[i].y > src[maxS].x + src[maxS].y) maxS = i;\n                if (src[i].x - src[i].y < src[minD].x - src[minD].y) minD = i;\n                if (src[i].x - src[i].y > src[maxD].x - src[maxD].y) maxD = i;\n            }\n            add(minX); add(maxX); add(minY); add(maxY);\n            add(minS); add(maxS); add(minD); add(maxD);\n\n            // nearest to corners\n            vector<Pt> corners = {{0,0}, {0,N-1}, {N-1,0}, {N-1,N-1}};\n            for (auto c : corners) {\n                int best = 0, bestd = manhattan(src[0], c);\n                for (int i = 1; i < Q; i++) {\n                    int d = manhattan(src[i], c);\n                    if (d < bestd) {\n                        bestd = d;\n                        best = i;\n                    }\n                }\n                add(best);\n            }\n\n            // near / far from centroid\n            double cx = 0, cy = 0;\n            for (auto &p : src) {\n                cx += p.x;\n                cy += p.y;\n            }\n            cx /= Q;\n            cy /= Q;\n\n            int nearC = 0, farC = 0;\n            double bestNear = 1e100, bestFar = -1.0;\n            for (int i = 0; i < Q; i++) {\n                double dx = src[i].x - cx;\n                double dy = src[i].y - cy;\n                double v = dx * dx + dy * dy;\n                if (v < bestNear) {\n                    bestNear = v;\n                    nearC = i;\n                }\n                if (v > bestFar) {\n                    bestFar = v;\n                    farC = i;\n                }\n            }\n            add(nearC);\n            add(farC);\n\n            // quartiles by x+y and x-y\n            vector<int> ord(Q);\n            iota(ord.begin(), ord.end(), 0);\n\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                int va = src[a].x + src[a].y;\n                int vb = src[b].x + src[b].y;\n                if (va != vb) return va < vb;\n                return a < b;\n            });\n            add(ord[0]);\n            add(ord[Q / 4]);\n            add(ord[Q / 2]);\n            add(ord[(3 * Q) / 4]);\n            add(ord[Q - 1]);\n\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                int va = src[a].x - src[a].y;\n                int vb = src[b].x - src[b].y;\n                if (va != vb) return va < vb;\n                return a < b;\n            });\n            add(ord[0]);\n            add(ord[Q / 4]);\n            add(ord[Q / 2]);\n            add(ord[(3 * Q) / 4]);\n            add(ord[Q - 1]);\n\n            if (startCandidates.empty()) add(0);\n        }\n    }\n\n    auto simulate = [&](int h, int startIdx, vector<Event>* rec) -> long long {\n        // startIdx is picked during setup turn 1.\n        // Then repeat:\n        //   collect until load==h (or no source remains)\n        //   deliver all carried items\n        vector<int> remS, remT;\n        remS.reserve(Q - 1);\n        remT.reserve(Q);\n        for (int i = 0; i < Q; i++) {\n            if (i != startIdx) remS.push_back(i);\n            remT.push_back(i);\n        }\n\n        if (rec) {\n            rec->clear();\n            rec->reserve(2 * Q - 1);\n        }\n\n        long long cost = 2; // 2 setup turns\n        bool curIsSource = true;\n        int curIdx = startIdx;\n        int load = 1;\n\n        while (!remS.empty() || load > 0) {\n            while (load < h && !remS.empty()) {\n                int bestPos = -1;\n                int bestIdx = -1;\n                int bestDist = INT_MAX;\n\n                if (curIsSource) {\n                    const auto& row = SS[curIdx];\n                    for (int pos = 0; pos < (int)remS.size(); pos++) {\n                        int j = remS[pos];\n                        int d = row[j];\n                        if (d < bestDist) {\n                            bestDist = d;\n                            bestIdx = j;\n                            bestPos = pos;\n                        }\n                    }\n                } else {\n                    const auto& row = TS[curIdx];\n                    for (int pos = 0; pos < (int)remS.size(); pos++) {\n                        int j = remS[pos];\n                        int d = row[j];\n                        if (d < bestDist) {\n                            bestDist = d;\n                            bestIdx = j;\n                            bestPos = pos;\n                        }\n                    }\n                }\n\n                cost += bestDist;\n                curIsSource = true;\n                curIdx = bestIdx;\n                load++;\n\n                if (rec) rec->push_back({true, bestIdx});\n\n                remS[bestPos] = remS.back();\n                remS.pop_back();\n            }\n\n            while (load > 0) {\n                int bestPos = -1;\n                int bestIdx = -1;\n                int bestDist = INT_MAX;\n\n                if (curIsSource) {\n                    const auto& row = ST[curIdx];\n                    for (int pos = 0; pos < (int)remT.size(); pos++) {\n                        int j = remT[pos];\n                        int d = row[j];\n                        if (d < bestDist) {\n                            bestDist = d;\n                            bestIdx = j;\n                            bestPos = pos;\n                        }\n                    }\n                } else {\n                    const auto& row = TT[curIdx];\n                    for (int pos = 0; pos < (int)remT.size(); pos++) {\n                        int j = remT[pos];\n                        int d = row[j];\n                        if (d < bestDist) {\n                            bestDist = d;\n                            bestIdx = j;\n                            bestPos = pos;\n                        }\n                    }\n                }\n\n                cost += bestDist;\n                curIsSource = false;\n                curIdx = bestIdx;\n                load--;\n\n                if (rec) rec->push_back({false, bestIdx});\n\n                remT[bestPos] = remT.back();\n                remT.pop_back();\n            }\n        }\n\n        return cost;\n    };\n\n    int maxH = min(leafCount, Q);\n    long long bestCost = (1LL << 60);\n    int bestH = 1;\n    int bestStart = 0;\n\n    // If Q is small, evaluate all starts for all h.\n    // Otherwise, evaluate sampled starts for all h, then refine top few h with all starts.\n    const int ALL_START_THRESHOLD = 200;\n    if (Q <= ALL_START_THRESHOLD) {\n        for (int h = 1; h <= maxH; h++) {\n            for (int st = 0; st < Q; st++) {\n                long long c = simulate(h, st, nullptr);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestH = h;\n                    bestStart = st;\n                }\n            }\n        }\n    } else {\n        vector<long long> bestSampleForH(maxH + 1, (1LL << 60));\n        for (int h = 1; h <= maxH; h++) {\n            for (int st : startCandidates) {\n                long long c = simulate(h, st, nullptr);\n                bestSampleForH[h] = min(bestSampleForH[h], c);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestH = h;\n                    bestStart = st;\n                }\n            }\n        }\n\n        vector<int> hs(maxH);\n        iota(hs.begin(), hs.end(), 1);\n        sort(hs.begin(), hs.end(), [&](int a, int b) {\n            if (bestSampleForH[a] != bestSampleForH[b]) return bestSampleForH[a] < bestSampleForH[b];\n            return a < b;\n        });\n\n        int refineK = min(3, maxH);\n        for (int k = 0; k < refineK; k++) {\n            int h = hs[k];\n            for (int st = 0; st < Q; st++) {\n                long long c = simulate(h, st, nullptr);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestH = h;\n                    bestStart = st;\n                }\n            }\n        }\n    }\n\n    vector<Event> route;\n    simulate(bestH, bestStart, &route);\n\n    Pt root0 = src[bestStart];\n    vector<string> ops;\n    ops.reserve((size_t)bestCost + 10);\n\n    auto make_cmd = [&]() -> string {\n        return string(2 * Vp, '.');\n    };\n\n    // Setup turn 0: rotate all leaves 90 deg clockwise.\n    {\n        string cmd = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd[u] = 'R';\n        ops.push_back(cmd);\n    }\n\n    // Setup turn 1: rotate all leaves another 90 deg clockwise => all leaves on root.\n    // Pick the starting source with leaf vertex 2.\n    {\n        string cmd = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd[u] = 'R';\n        cmd[Vp + 2] = 'P'; // leaf vertex 2 picks\n        ops.push_back(cmd);\n    }\n\n    vector<int> holding(leafCount, 0);\n    holding[0] = 1; // leaf vertex 2 is holding after setup\n    Pt cur = root0;\n\n    auto emit_step = [&](char mv, bool doAction, bool pickup) {\n        string cmd = make_cmd();\n        cmd[0] = mv;\n\n        if (doAction) {\n            int chosen = -1;\n            if (pickup) {\n                for (int i = 0; i < leafCount; i++) {\n                    if (!holding[i]) {\n                        chosen = i;\n                        holding[i] = 1;\n                        break;\n                    }\n                }\n            } else {\n                for (int i = 0; i < leafCount; i++) {\n                    if (holding[i]) {\n                        chosen = i;\n                        holding[i] = 0;\n                        break;\n                    }\n                }\n            }\n            if (chosen < 0) chosen = 0; // should not happen\n            int vertex = 2 + chosen;\n            cmd[Vp + vertex] = 'P';\n        }\n\n        ops.push_back(cmd);\n    };\n\n    for (auto &ev : route) {\n        Pt p = ev.pickup ? src[ev.idx] : dst[ev.idx];\n\n        while (cur.x < p.x) {\n            cur.x++;\n            emit_step('D', cur.x == p.x && cur.y == p.y, ev.pickup);\n        }\n        while (cur.x > p.x) {\n            cur.x--;\n            emit_step('U', cur.x == p.x && cur.y == p.y, ev.pickup);\n        }\n        while (cur.y < p.y) {\n            cur.y++;\n            emit_step('R', cur.x == p.x && cur.y == p.y, ev.pickup);\n        }\n        while (cur.y > p.y) {\n            cur.y--;\n            emit_step('L', cur.x == p.x && cur.y == p.y, ev.pickup);\n        }\n    }\n\n    // Output\n    output_tree(root0.x, root0.y);\n    for (auto &cmd : ops) {\n        cout << cmd << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic constexpr int COORD_MAX = 100000;\nstatic constexpr int ENC_SHIFT = 17;\nstatic constexpr int ENC_MASK = (1 << ENC_SHIFT) - 1;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct GridData {\n    int G, sx, sy;\n    int W, H;\n    vector<int> xs, ys;   // boundaries\n    vector<int> w;        // cell weight\n};\n\nstruct Component {\n    vector<int> cells;\n    int prize = 0; // sum of original cell weights\n};\n\nstruct ComponentsResult {\n    vector<Component> comps;\n    vector<int> compId;   // -1 for non-selected\n    int bestCid = -1;     // among positive-prize components\n    int positiveCount = 0;\n};\n\nstruct Candidate {\n    vector<Pt> poly;\n    long long approx = 0;\n    int perim = 0;\n    int minx = 0, maxx = 0, miny = 0, maxy = 0;\n    uint64_t hash = 0;\n};\n\nstatic inline long long enc_xy(int x, int y) {\n    return (static_cast<long long>(x) << ENC_SHIFT) | y;\n}\n\nstatic inline Pt dec_xy(long long v) {\n    return Pt{static_cast<int>(v >> ENC_SHIFT), static_cast<int>(v & ENC_MASK)};\n}\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nstatic inline bool between_incl(int v, int a, int b) {\n    if (a > b) swap(a, b);\n    return a <= v && v <= b;\n}\n\nvector<int> create_bounds(int G, int shift) {\n    vector<int> res;\n    res.push_back(0);\n    int cur = 0;\n    if (shift > 0) {\n        res.push_back(shift);\n        cur = shift;\n    }\n    while (cur < COORD_MAX) {\n        cur = min(COORD_MAX, cur + G);\n        if (cur > res.back()) res.push_back(cur);\n    }\n    return res;\n}\n\nint coord_to_index(int v, int G, int shift, int cells) {\n    if (v == COORD_MAX) return cells - 1;\n    if (shift > 0 && v < shift) return 0;\n    int idx;\n    if (shift == 0) idx = v / G;\n    else idx = 1 + (v - shift) / G;\n    if (idx < 0) idx = 0;\n    if (idx >= cells) idx = cells - 1;\n    return idx;\n}\n\nGridData build_grid(const vector<Pt>& macks, const vector<Pt>& sards, int G, int sx, int sy) {\n    GridData gd;\n    gd.G = G; gd.sx = sx; gd.sy = sy;\n    gd.xs = create_bounds(G, sx);\n    gd.ys = create_bounds(G, sy);\n    gd.W = (int)gd.xs.size() - 1;\n    gd.H = (int)gd.ys.size() - 1;\n    gd.w.assign(gd.W * gd.H, 0);\n\n    auto id = [&](int x, int y) { return y * gd.W + x; };\n\n    for (const auto& p : macks) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]++;\n    }\n    for (const auto& p : sards) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]--;\n    }\n    return gd;\n}\n\nlong long region_sum(const vector<char>& occ, const vector<int>& w) {\n    long long s = 0;\n    int n = (int)occ.size();\n    for (int i = 0; i < n; i++) if (occ[i]) s += w[i];\n    return s;\n}\n\nvector<char> best_rectangle_region(const GridData& gd) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    long long best = LLONG_MIN;\n    int bestL = -1, bestR = -1, bestB = -1, bestT = -1;\n\n    vector<long long> tmp(H);\n    for (int L = 0; L < W; L++) {\n        fill(tmp.begin(), tmp.end(), 0);\n        for (int R = L; R < W; R++) {\n            for (int y = 0; y < H; y++) tmp[y] += gd.w[id(R, y)];\n\n            long long cur = 0;\n            int start = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = tmp[y];\n                    start = y;\n                } else {\n                    cur += tmp[y];\n                }\n                if (cur > best) {\n                    best = cur;\n                    bestL = L; bestR = R; bestB = start; bestT = y;\n                }\n            }\n        }\n    }\n\n    vector<char> occ(W * H, 0);\n    if (best <= 0 || bestL < 0) return occ;\n\n    for (int y = bestB; y <= bestT; y++) {\n        for (int x = bestL; x <= bestR; x++) {\n            occ[id(x, y)] = 1;\n        }\n    }\n    return occ;\n}\n\nvector<char> graph_cut_select(const GridData& gd, int lambda) {\n    int W = gd.W, H = gd.H;\n    int V = W * H;\n    int S = V, T = V + 1;\n    mf_graph<long long> mf(V + 2);\n\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int ww = gd.w[v];\n            if (ww >= 0) mf.add_edge(S, v, ww);\n            else mf.add_edge(v, T, -ww);\n\n            int border = 0;\n            if (x == 0) border++;\n            if (x == W - 1) border++;\n            if (y == 0) border++;\n            if (y == H - 1) border++;\n            if (border) mf.add_edge(v, T, 1LL * lambda * border);\n\n            if (x + 1 < W) {\n                int u = id(x + 1, y);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n            if (y + 1 < H) {\n                int u = id(x, y + 1);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n        }\n    }\n\n    mf.flow(S, T);\n    auto cut = mf.min_cut(S);\n    vector<char> sel(V, 0);\n    for (int i = 0; i < V; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nComponentsResult get_components(const vector<char>& sel, const vector<int>& w, int W, int H) {\n    ComponentsResult res;\n    int V = W * H;\n    res.compId.assign(V, -1);\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    int cid = 0;\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int s = id(x, y);\n            if (!sel[s] || res.compId[s] != -1) continue;\n\n            queue<int> q;\n            q.push(s);\n            res.compId[s] = cid;\n            Component comp;\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                comp.cells.push_back(v);\n                comp.prize += w[v];\n\n                int vx = v % W, vy = v / W;\n                static const int dx[4] = {1, -1, 0, 0};\n                static const int dy[4] = {0, 0, 1, -1};\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = vx + dx[dir], ny = vy + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (!sel[u] || res.compId[u] != -1) continue;\n                    res.compId[u] = cid;\n                    q.push(u);\n                }\n            }\n\n            res.comps.push_back(std::move(comp));\n            cid++;\n        }\n    }\n\n    int bestPrize = INT_MIN;\n    for (int i = 0; i < (int)res.comps.size(); i++) {\n        if (res.comps[i].prize > 0) {\n            res.positiveCount++;\n            if (res.comps[i].prize > bestPrize) {\n                bestPrize = res.comps[i].prize;\n                res.bestCid = i;\n            }\n        }\n    }\n    return res;\n}\n\nvoid fill_holes(vector<char>& occ, int W, int H) {\n    int PW = W + 2, PH = H + 2;\n    vector<char> vis(PW * PH, 0);\n\n    auto pid = [&](int x, int y) { return y * PW + x; };\n    auto blocked = [&](int x, int y) -> bool {\n        if (x == 0 || x == W + 1 || y == 0 || y == H + 1) return false;\n        return occ[(y - 1) * W + (x - 1)];\n    };\n\n    queue<int> q;\n    q.push(pid(0, 0));\n    vis[pid(0, 0)] = 1;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % PW, y = v / PW;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (nx < 0 || nx >= PW || ny < 0 || ny >= PH) continue;\n            int u = pid(nx, ny);\n            if (vis[u] || blocked(nx, ny)) continue;\n            vis[u] = 1;\n            q.push(u);\n        }\n    }\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = y * W + x;\n            if (!occ[v] && !vis[pid(x + 1, y + 1)]) occ[v] = 1;\n        }\n    }\n}\n\nvoid add_positive_neighbors(vector<char>& occ, const vector<int>& w, int W, int H) {\n    int V = W * H;\n    queue<int> q;\n    for (int i = 0; i < V; i++) if (occ[i]) q.push(i);\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (!inside(nx, ny)) continue;\n            int u = id(nx, ny);\n            if (!occ[u] && w[u] > 0) {\n                occ[u] = 1;\n                q.push(u);\n            }\n        }\n    }\n}\n\nbool is_boundary_cell(const vector<char>& occ, int v, int W, int H) {\n    if (!occ[v]) return false;\n    int x = v % W, y = v / W;\n    if (x == 0 || x == W - 1 || y == 0 || y == H - 1) return true;\n    if (!occ[v - 1] || !occ[v + 1] || !occ[v - W] || !occ[v + W]) return true;\n    return false;\n}\n\nbool can_remove_connected(const vector<char>& occ, int rem, int W, int H, int occCount) {\n    if (occCount <= 1) return false;\n\n    int start = -1;\n    int V = W * H;\n    for (int i = 0; i < V; i++) {\n        if (i != rem && occ[i]) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return false;\n\n    vector<char> vis(V, 0);\n    queue<int> q;\n    q.push(start);\n    vis[start] = 1;\n    int seen = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (!inside(nx, ny)) continue;\n            int u = id(nx, ny);\n            if (u == rem || !occ[u] || vis[u]) continue;\n            vis[u] = 1;\n            seen++;\n            q.push(u);\n        }\n    }\n    return seen == occCount - 1;\n}\n\nvoid prune_negative_boundary(vector<char>& occ, const vector<int>& w, int W, int H) {\n    int occCount = 0;\n    for (char c : occ) if (c) occCount++;\n\n    for (int round = 0; round < 2; round++) {\n        vector<int> cand;\n        for (int i = 0; i < (int)occ.size(); i++) {\n            if (occ[i] && w[i] < 0 && is_boundary_cell(occ, i, W, H)) cand.push_back(i);\n        }\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            return w[a] < w[b];\n        });\n        if ((int)cand.size() > 80) cand.resize(80);\n\n        bool changed = false;\n        for (int v : cand) {\n            if (occCount <= 1) break;\n            if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n            if (can_remove_connected(occ, v, W, H, occCount)) {\n                occ[v] = 0;\n                occCount--;\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\nvoid postprocess_extra(vector<char>& occ, const vector<int>& w, int W, int H) {\n    fill_holes(occ, W, H);\n    add_positive_neighbors(occ, w, W, H);\n    fill_holes(occ, W, H);\n    prune_negative_boundary(occ, w, W, H);\n    fill_holes(occ, W, H);\n}\n\nvector<char> greedy_connect(\n    const vector<char>& sel,\n    const ComponentsResult& cr,\n    const vector<int>& w,\n    int W, int H\n) {\n    int V = W * H;\n    vector<char> occ(V, 0);\n    if (cr.bestCid < 0) return occ;\n\n    int C = (int)cr.comps.size();\n    vector<char> goodComp(C, 0);\n    for (int i = 0; i < C; i++) goodComp[i] = (cr.comps[i].prize > 0);\n\n    vector<char> added(C, 0);\n    for (int v : cr.comps[cr.bestCid].cells) occ[v] = 1;\n    added[cr.bestCid] = 1;\n    int addCnt = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    auto is_good_sel = [&](int v) -> bool {\n        if (!sel[v]) return false;\n        int cid = cr.compId[v];\n        return cid >= 0 && goodComp[cid];\n    };\n\n    auto enter_cost = [&](int v) -> int {\n        if (occ[v]) return 0;\n        if (is_good_sel(v)) return 0;\n        if (w[v] > 0) return max(1, 10 - 3 * w[v]);\n        return 10 + 10 * (-w[v]);\n    };\n\n    for (int iter = 0; iter < 12; iter++) {\n        const int INF = 1e9;\n        vector<int> dist(V, INF), parent(V, -1);\n        priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n\n        for (int v = 0; v < V; v++) {\n            if (occ[v]) {\n                dist[v] = 0;\n                pq.push({0, v});\n            }\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            int x = v % W, y = v / W;\n            static const int dx[4] = {1, -1, 0, 0};\n            static const int dy[4] = {0, 0, 1, -1};\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!inside(nx, ny)) continue;\n                int u = id(nx, ny);\n                int nd = d + enter_cost(u);\n                if (nd < dist[u]) {\n                    dist[u] = nd;\n                    parent[u] = v;\n                    pq.push({nd, u});\n                }\n            }\n        }\n\n        long long bestGain = 0;\n        int chooseCid = -1;\n        int chooseCell = -1;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!goodComp[cid] || added[cid]) continue;\n            int bestDist = INF;\n            int bestCell = -1;\n            for (int v : cr.comps[cid].cells) {\n                if (dist[v] < bestDist) {\n                    bestDist = dist[v];\n                    bestCell = v;\n                }\n            }\n            if (bestCell == -1) continue;\n            long long gain = 10LL * cr.comps[cid].prize - bestDist;\n            if (gain > bestGain) {\n                bestGain = gain;\n                chooseCid = cid;\n                chooseCell = bestCell;\n            }\n        }\n\n        if (chooseCid == -1) break;\n\n        vector<char> touched(C, 0);\n        int v = chooseCell;\n        while (v != -1 && !occ[v]) {\n            occ[v] = 1;\n            if (is_good_sel(v)) touched[cr.compId[v]] = 1;\n            v = parent[v];\n        }\n        touched[chooseCid] = 1;\n\n        bool anyNew = false;\n        for (int cid = 0; cid < C; cid++) {\n            if (!touched[cid] || added[cid]) continue;\n            added[cid] = 1;\n            anyNew = true;\n            addCnt++;\n            for (int u : cr.comps[cid].cells) occ[u] = 1;\n        }\n        if (!anyNew) break;\n    }\n\n    return occ;\n}\n\nvector<Pt> build_polygon(const GridData& gd, const vector<char>& occ) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    unordered_map<long long, long long> nxt;\n    nxt.reserve((size_t)occ.size() * 2 + 16);\n    bool bad = false;\n    long long start = -1;\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) {\n        long long a = enc_xy(x1, y1);\n        long long b = enc_xy(x2, y2);\n        auto it = nxt.find(a);\n        if (it != nxt.end() && it->second != b) bad = true;\n        nxt[a] = b;\n        if (start == -1 || a < start) start = a;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            if (!occ[v]) continue;\n            int x0 = gd.xs[x], x1 = gd.xs[x + 1];\n            int y0 = gd.ys[y], y1 = gd.ys[y + 1];\n\n            if (y == 0 || !occ[id(x, y - 1)]) add_edge(x0, y0, x1, y0);\n            if (x == W - 1 || !occ[id(x + 1, y)]) add_edge(x1, y0, x1, y1);\n            if (y == H - 1 || !occ[id(x, y + 1)]) add_edge(x1, y1, x0, y1);\n            if (x == 0 || !occ[id(x - 1, y)]) add_edge(x0, y1, x0, y0);\n        }\n    }\n\n    if (bad || start == -1) return {};\n\n    vector<Pt> poly;\n    long long cur = start;\n    int steps = 0;\n\n    while (true) {\n        poly.push_back(dec_xy(cur));\n        auto it = nxt.find(cur);\n        if (it == nxt.end()) return {};\n        cur = it->second;\n        steps++;\n        if (cur == start) break;\n        if (steps > (int)nxt.size() + 5) return {};\n    }\n\n    if (steps != (int)nxt.size()) return {};\n\n    auto collinear = [&](const Pt& a, const Pt& b, const Pt& c) {\n        return (a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y);\n    };\n\n    bool changed = true;\n    while (changed && (int)poly.size() > 4) {\n        changed = false;\n        vector<Pt> np;\n        int m = (int)poly.size();\n        np.reserve(m);\n        for (int i = 0; i < m; i++) {\n            const Pt& prev = poly[(i - 1 + m) % m];\n            const Pt& curp = poly[i];\n            const Pt& nextp = poly[(i + 1) % m];\n            if (collinear(prev, curp, nextp)) {\n                changed = true;\n            } else {\n                np.push_back(curp);\n            }\n        }\n        poly.swap(np);\n    }\n\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return {};\n\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    for (const auto& p : poly) {\n        long long e = enc_xy(p.x, p.y);\n        if (!seen.insert(e).second) return {};\n    }\n\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        perim += manhattan(poly[i], poly[(i + 1) % poly.size()]);\n    }\n    if (perim > 400000) return {};\n\n    return poly;\n}\n\nuint64_t hash_poly(const vector<Pt>& poly) {\n    uint64_t h = 1469598103934665603ULL;\n    for (const auto& p : poly) {\n        uint64_t v = (uint64_t)p.x * 1000003ULL + (uint64_t)p.y + 0x9e3779b97f4a7c15ULL;\n        h ^= v;\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)poly.size() + 0x517cc1b727220a95ULL;\n    return h;\n}\n\nCandidate make_candidate(vector<Pt> poly, long long approx) {\n    Candidate c;\n    c.poly = std::move(poly);\n    c.approx = approx;\n    c.perim = 0;\n    c.minx = c.maxx = c.poly[0].x;\n    c.miny = c.maxy = c.poly[0].y;\n    for (int i = 0; i < (int)c.poly.size(); i++) {\n        c.perim += manhattan(c.poly[i], c.poly[(i + 1) % c.poly.size()]);\n        c.minx = min(c.minx, c.poly[i].x);\n        c.maxx = max(c.maxx, c.poly[i].x);\n        c.miny = min(c.miny, c.poly[i].y);\n        c.maxy = max(c.maxy, c.poly[i].y);\n    }\n    c.hash = hash_poly(c.poly);\n    return c;\n}\n\nvoid try_add_candidate(vector<Candidate>& cands, const GridData& gd, const vector<char>& occ) {\n    long long approx = region_sum(occ, gd.w);\n    if (approx < 0) return;\n    auto poly = build_polygon(gd, occ);\n    if (poly.empty()) return;\n    cands.push_back(make_candidate(std::move(poly), approx));\n}\n\nbool contains_point(const Candidate& c, const Pt& p) {\n    if (p.x < c.minx || p.x > c.maxx || p.y < c.miny || p.y > c.maxy) return false;\n\n    bool inside = false;\n    int m = (int)c.poly.size();\n    for (int i = 0; i < m; i++) {\n        const Pt& a = c.poly[i];\n        const Pt& b = c.poly[(i + 1) % m];\n\n        if (a.x == b.x) {\n            if (p.x == a.x && between_incl(p.y, a.y, b.y)) return true;\n            if ((a.y > p.y) != (b.y > p.y) && a.x > p.x) inside = !inside;\n        } else {\n            if (p.y == a.y && between_incl(p.x, a.x, b.x)) return true;\n        }\n    }\n    return inside;\n}\n\nint exact_score(const Candidate& c, const vector<pair<Pt,int>>& fishes) {\n    int diff = 0;\n    for (const auto& [p, sgn] : fishes) {\n        if (contains_point(c, p)) diff += sgn;\n    }\n    return max(0, diff + 1);\n}\n\nvector<Pt> find_empty_square(const unordered_set<long long>& pts) {\n    auto has = [&](int x, int y) -> bool {\n        return pts.find(1LL * x * (COORD_MAX + 1) + y) != pts.end();\n    };\n    for (int x = 0; x <= 1000; x++) {\n        for (int y = 0; y <= 1000; y++) {\n            if (x + 1 > COORD_MAX || y + 1 > COORD_MAX) continue;\n            if (!has(x, y) && !has(x + 1, y) && !has(x, y + 1) && !has(x + 1, y + 1)) {\n                return {{x, y}, {x + 1, y}, {x + 1, y + 1}, {x, y + 1}};\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<Pt> macks(N), sards(N);\n    unordered_set<long long> allPts;\n    allPts.reserve((size_t)2 * N * 2);\n\n    for (int i = 0; i < N; i++) {\n        cin >> macks[i].x >> macks[i].y;\n        allPts.insert(1LL * macks[i].x * (COORD_MAX + 1) + macks[i].y);\n    }\n    for (int i = 0; i < N; i++) {\n        cin >> sards[i].x >> sards[i].y;\n        allPts.insert(1LL * sards[i].x * (COORD_MAX + 1) + sards[i].y);\n    }\n\n    vector<pair<Pt,int>> fishes;\n    fishes.reserve(2 * N);\n    for (auto& p : macks) fishes.push_back({p, +1});\n    for (auto& p : sards) fishes.push_back({p, -1});\n\n    vector<Candidate> cands;\n    cands.reserve(256);\n\n    vector<int> Gs = {1400, 1800, 2300, 3000};\n    vector<int> lambdas = {1, 2};\n\n    for (int G : Gs) {\n        vector<pair<int,int>> shifts = {\n            {0, 0},\n            {0, G / 2},\n            {G / 2, 0},\n            {G / 2, G / 2}\n        };\n\n        for (auto [sx, sy] : shifts) {\n            GridData gd = build_grid(macks, sards, G, sx, sy);\n\n            // Rectangle baseline\n            {\n                auto occ = best_rectangle_region(gd);\n                try_add_candidate(cands, gd, occ);\n            }\n\n            for (int lambda : lambdas) {\n                auto sel = graph_cut_select(gd, lambda);\n                auto cr = get_components(sel, gd.w, gd.W, gd.H);\n                if (cr.bestCid < 0) continue;\n\n                // Best component: raw\n                {\n                    vector<char> occ(gd.W * gd.H, 0);\n                    for (int v : cr.comps[cr.bestCid].cells) occ[v] = 1;\n                    fill_holes(occ, gd.W, gd.H);\n                    try_add_candidate(cands, gd, occ);\n\n                    // Best component: refined\n                    auto occ2 = occ;\n                    postprocess_extra(occ2, gd.w, gd.W, gd.H);\n                    try_add_candidate(cands, gd, occ2);\n                }\n\n                // Greedy connected union\n                if (cr.positiveCount >= 2) {\n                    auto occ = greedy_connect(sel, cr, gd.w, gd.W, gd.H);\n                    fill_holes(occ, gd.W, gd.H);\n                    try_add_candidate(cands, gd, occ);\n\n                    auto occ2 = occ;\n                    postprocess_extra(occ2, gd.w, gd.W, gd.H);\n                    try_add_candidate(cands, gd, occ2);\n                }\n            }\n        }\n    }\n\n    // Fallback small empty square\n    Candidate best = make_candidate(find_empty_square(allPts), 0);\n    int bestScore = exact_score(best, fishes);\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.perim != b.perim) return a.perim < b.perim;\n        return a.poly.size() < b.poly.size();\n    });\n\n    const int MAX_EVAL = 120;\n    unordered_set<uint64_t> used;\n    used.reserve(MAX_EVAL * 2 + 16);\n\n    int evalCnt = 0;\n    for (const auto& c : cands) {\n        if (!used.insert(c.hash).second) continue;\n        int sc = exact_score(c, fishes);\n        if (sc > bestScore) {\n            bestScore = sc;\n            best = c;\n        }\n        evalCnt++;\n        if (evalCnt >= MAX_EVAL) break;\n    }\n\n    cout << best.poly.size() << '\\n';\n    for (auto& p : best.poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Dim {\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 score = 1e100;\n    uint64_t hash = 0;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstatic uint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    h ^= splitmix64((uint64_t)ops.size());\n    for (const auto& op : ops) {\n        uint64_t v = 0;\n        v ^= (uint64_t)(op.p + 1) * 1000003ULL;\n        v ^= (uint64_t)(op.r + 7) * 10007ULL;\n        v ^= (uint64_t)(unsigned char)(op.d) * 911382323ULL;\n        v ^= (uint64_t)(op.b + 2) * 972663749ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\nstatic bool overlap1D(double l1, double r1, double l2, double r2) {\n    const double EPS = 1e-9;\n    return max(l1, l2) + EPS < min(r1, r2);\n}\n\nstatic double exact_score(const vector<Dim>& dims, const vector<Op>& ops) {\n    int N = (int)dims.size();\n    vector<double> x1(N, 0), y1(N, 0), x2(N, 0), y2(N, 0);\n    vector<char> placed(N, 0), used(N, 0);\n\n    double W = 0, H = 0;\n\n    for (const auto& op : ops) {\n        int p = op.p;\n        double w = op.r ? dims[p].h : dims[p].w;\n        double h = op.r ? dims[p].w : dims[p].h;\n\n        double x = 0, y = 0;\n\n        if (op.d == 'U') {\n            x = (op.b == -1 ? 0.0 : x2[op.b]);\n            y = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(x, x + w, x1[j], x2[j])) {\n                    y = max(y, y2[j]);\n                }\n            }\n        } else {\n            y = (op.b == -1 ? 0.0 : y2[op.b]);\n            x = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(y, y + h, y1[j], y2[j])) {\n                    x = max(x, x2[j]);\n                }\n            }\n        }\n\n        x1[p] = x; y1[p] = y;\n        x2[p] = x + w; y2[p] = y + h;\n        placed[p] = used[p] = 1;\n\n        W = max(W, x2[p]);\n        H = max(H, y2[p]);\n    }\n\n    double penalty = 0.0;\n    for (int i = 0; i < N; i++) {\n        if (!used[i]) penalty += dims[i].w + dims[i].h;\n    }\n    return W + H + penalty;\n}\n\nstatic vector<Op> make_single_line(int N, char dir, int rot) {\n    vector<Op> ops;\n    ops.reserve(N);\n    for (int i = 0; i < N; i++) {\n        ops.push_back({i, rot, dir, -1});\n    }\n    return ops;\n}\n\nstatic pair<long long, long long> query_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n\n    long long W, H;\n    if (!(cin >> W >> H)) exit(0);\n    if (W < 0 || H < 0) exit(0);\n    return {W, H};\n}\n\nstruct Node {\n    int parent = -1;\n    unsigned char act = 0; // 0=skip, 1=continue/start, 2=new group\n    unsigned char rot = 0;\n    double maxDoneA = 0; // max completed line length in A\n    double sumDoneB = 0; // sum completed line thickness in B\n    double curA = 0;     // current line length in A\n    double curB = 0;     // current line thickness in B\n    double pen = 0;      // omitted penalty\n    double eval = 0;\n};\n\nstatic inline double current_exact_of(const Node& s) {\n    return s.pen + max(s.maxDoneA, s.curA) + s.sumDoneB + s.curB;\n}\n\n// dir='L': rows  -> A=width,  B=height\n// dir='U': cols  -> A=height, B=width\nstatic Candidate beam_shelf(\n    const vector<Dim>& sample,\n    const vector<Dim>& base,\n    char dir,\n    double targetA,\n    int beamWidth,\n    double omitMul\n) {\n    int N = (int)sample.size();\n    vector<double> a0(N), b0(N), a1(N), b1(N), remArea(N + 1);\n\n    for (int i = 0; i < N; i++) {\n        double w = sample[i].w, h = sample[i].h;\n        if (dir == 'L') {\n            a0[i] = w; b0[i] = h;\n            a1[i] = h; b1[i] = w;\n        } else {\n            a0[i] = h; b0[i] = w;\n            a1[i] = w; b1[i] = h;\n        }\n    }\n\n    remArea[N] = 0.0;\n    for (int i = N - 1; i >= 0; i--) {\n        remArea[i] = remArea[i + 1] + sample[i].w * sample[i].h;\n    }\n\n    auto calc_eval = [&](double maxDoneA, double sumDoneB, double curA, double curB, double pen, int nexti) -> double {\n        double nowA = max(maxDoneA, curA);\n        double assumedA = max(nowA, targetA);\n        if (assumedA < 1.0) assumedA = 1.0;\n        return pen + assumedA + sumDoneB + curB + remArea[nexti] / assumedA;\n    };\n\n    vector<Node> nodes;\n    nodes.reserve(1 + (size_t)N * beamWidth * 5 + 16);\n    nodes.push_back(Node());\n    nodes[0].eval = calc_eval(0, 0, 0, 0, 0, 0);\n\n    vector<int> beam, nxt;\n    beam.push_back(0);\n\n    auto cmp = [&](int x, int y) {\n        if (nodes[x].eval != nodes[y].eval) return nodes[x].eval < nodes[y].eval;\n        return current_exact_of(nodes[x]) < current_exact_of(nodes[y]);\n    };\n\n    for (int i = 0; i < N; i++) {\n        nxt.clear();\n        nxt.reserve((size_t)beam.size() * 5 + 8);\n\n        for (int id : beam) {\n            const Node& s = nodes[id];\n\n            // skip\n            {\n                Node t = s;\n                t.parent = id;\n                t.act = 0;\n                t.rot = 0;\n                t.pen = s.pen + omitMul * (sample[i].w + sample[i].h);\n                t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                nodes.push_back(t);\n                nxt.push_back((int)nodes.size() - 1);\n            }\n\n            for (int r = 0; r < 2; r++) {\n                double a = (r ? a1[i] : a0[i]);\n                double b = (r ? b1[i] : b0[i]);\n\n                // no used item yet -> start first line\n                if (s.curA == 0.0 && s.curB == 0.0 && s.maxDoneA == 0.0 && s.sumDoneB == 0.0) {\n                    Node t;\n                    t.parent = id;\n                    t.act = 1;\n                    t.rot = (unsigned char)r;\n                    t.maxDoneA = 0.0;\n                    t.sumDoneB = 0.0;\n                    t.curA = a;\n                    t.curB = b;\n                    t.pen = s.pen;\n                    t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                    nodes.push_back(t);\n                    nxt.push_back((int)nodes.size() - 1);\n                } else {\n                    // continue current line\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 1;\n                        t.rot = (unsigned char)r;\n                        t.curA = s.curA + a;\n                        t.curB = max(s.curB, b);\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                    // start new line\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 2;\n                        t.rot = (unsigned char)r;\n                        t.maxDoneA = max(s.maxDoneA, s.curA);\n                        t.sumDoneB = s.sumDoneB + s.curB;\n                        t.curA = a;\n                        t.curB = b;\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                }\n            }\n        }\n\n        if ((int)nxt.size() > beamWidth) {\n            nth_element(nxt.begin(), nxt.begin() + beamWidth, nxt.end(), cmp);\n            nxt.resize(beamWidth);\n        }\n        sort(nxt.begin(), nxt.end(), cmp);\n        beam.swap(nxt);\n    }\n\n    int bestId = beam[0];\n    double bestExact = current_exact_of(nodes[bestId]);\n    for (int id : beam) {\n        double sc = current_exact_of(nodes[id]);\n        if (sc < bestExact) {\n            bestExact = sc;\n            bestId = id;\n        }\n    }\n\n    vector<int> act(N, 0), rot(N, 0);\n    int cur = bestId;\n    for (int i = N - 1; i >= 0; i--) {\n        act[i] = nodes[cur].act;\n        rot[i] = nodes[cur].rot;\n        cur = nodes[cur].parent;\n    }\n\n    vector<vector<pair<int,int>>> groups;\n    bool started = false;\n    for (int i = 0; i < N; i++) {\n        if (act[i] == 0) continue;\n        if (!started || act[i] == 2) {\n            groups.emplace_back();\n            started = true;\n        }\n        groups.back().push_back({i, rot[i]});\n    }\n\n    vector<int> reps;\n    reps.reserve(groups.size());\n\n    auto metricB_base = [&](int idx, int r) -> double {\n        if (dir == 'L') {\n            return r ? base[idx].w : base[idx].h; // row height\n        } else {\n            return r ? base[idx].h : base[idx].w; // column width\n        }\n    };\n\n    for (auto& g : groups) {\n        int bestIdx = g[0].first;\n        double bestM = metricB_base(g[0].first, g[0].second);\n        for (auto [idx, r] : g) {\n            double m = metricB_base(idx, r);\n            if (m > bestM) {\n                bestM = m;\n                bestIdx = idx;\n            }\n        }\n        reps.push_back(bestIdx);\n    }\n\n    vector<Op> ops;\n    for (int gi = 0; gi < (int)groups.size(); gi++) {\n        int bref = (gi == 0 ? -1 : reps[gi - 1]);\n        for (auto [idx, r] : groups[gi]) {\n            ops.push_back({idx, r, dir, bref});\n        }\n    }\n\n    Candidate cand;\n    cand.ops = move(ops);\n    cand.score = exact_score(base, cand.ops);\n    cand.hash = hash_ops(cand.ops);\n    return cand;\n}\n\nstatic vector<Dim> sample_posterior(\n    const vector<Dim>& base,\n    double sigma,\n    double alpha,\n    double tauW,\n    double tauH,\n    mt19937_64& rng\n) {\n    int N = (int)base.size();\n    static normal_distribution<double> nd(0.0, 1.0);\n\n    vector<double> uw(N), uh(N);\n    double sumUw = 0.0, sumUh = 0.0;\n    for (int i = 0; i < N; i++) {\n        uw[i] = nd(rng) * alpha * sigma;\n        uh[i] = nd(rng) * alpha * sigma;\n        sumUw += uw[i];\n        sumUh += uh[i];\n    }\n\n    double corrW = -sumUw / (N + tauW);\n    double corrH = -sumUh / (N + tauH);\n\n    vector<Dim> out(N);\n    for (int i = 0; i < N; i++) {\n        out[i].w = max(1.0, base[i].w + uw[i] + corrW);\n        out[i].h = max(1.0, base[i].h + uh[i] + corrH);\n    }\n    return out;\n}\n\nstatic double total_area(const vector<Dim>& dims) {\n    long double s = 0;\n    for (auto& d : dims) s += (long double)d.w * d.h;\n    return (double)s;\n}\n\nstatic vector<Candidate> generate_pool(\n    const vector<Dim>& base,\n    int remainingTurns,\n    double sigma,\n    double tauW,\n    double tauH,\n    mt19937_64& rng\n) {\n    int N = (int)base.size();\n    int Bdet = (N <= 60 ? 520 : 360);\n    int Bbig = (N <= 60 ? 700 : 520);\n    int Brand = (N <= 60 ? 220 : 140);\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    auto try_add = [&](Candidate cand) {\n        if (seen.insert(cand.hash).second) {\n            pool.push_back(move(cand));\n        }\n    };\n\n    double baseTarget = sqrt(max(1.0, total_area(base)));\n\n    vector<double> scales = {0.50, 0.65, 0.80, 0.95, 1.10, 1.30, 1.55, 1.85};\n\n    // Deterministic candidates on posterior mean.\n    for (double sc : scales) {\n        try_add(beam_shelf(base, base, 'L', baseTarget * sc, Bdet, 1.20));\n        try_add(beam_shelf(base, base, 'U', baseTarget * sc, Bdet, 1.20));\n    }\n    for (double om : {1.05, 1.35}) {\n        try_add(beam_shelf(base, base, 'L', baseTarget, Bbig, om));\n        try_add(beam_shelf(base, base, 'U', baseTarget, Bbig, om));\n    }\n\n    // Randomized posterior samples.\n    const int maxPool = min(340, max(70, remainingTurns + 60));\n    auto t0 = chrono::steady_clock::now();\n    uniform_real_distribution<double> ur(0.0, 1.0);\n    uniform_real_distribution<double> ul(log(0.45), log(2.20));\n\n    vector<double> alphas = {0.35, 0.70, 1.10};\n    vector<double> omits  = {1.00, 1.15, 1.30};\n\n    int attempts = 0;\n    while ((int)pool.size() < maxPool) {\n        auto now = chrono::steady_clock::now();\n        double sec = chrono::duration<double>(now - t0).count();\n        if (sec > 1.45) break;\n\n        double alpha = alphas[(uint64_t)rng() % alphas.size()];\n        auto sample = sample_posterior(base, sigma, alpha, tauW, tauH, rng);\n        double tgt = sqrt(max(1.0, total_area(sample))) * exp(ul(rng));\n        char dir = (rng() & 1) ? 'L' : 'U';\n        double om = omits[(uint64_t)rng() % omits.size()];\n        int bw = (attempts < 40 ? max(Brand, Bdet / 2) : Brand);\n\n        try_add(beam_shelf(sample, base, dir, tgt, bw, om));\n        attempts++;\n        if (attempts > 2000) break;\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.score < b.score;\n    });\n    return pool;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, T;\n    int sigma_i;\n    cin >> N >> T >> sigma_i;\n    double sigma = sigma_i;\n\n    vector<Dim> obs(N);\n    for (int i = 0; i < N; i++) {\n        cin >> obs[i].w >> obs[i].h;\n    }\n\n    mt19937_64 rng(1234567890123456789ULL);\n\n    int calibTurns = (T >= 24 ? 4 : 2);\n    vector<double> widthMeasures, heightMeasures;\n\n    // Calibration 1: all in one row, no rotation -> width = sum(w)\n    {\n        auto resp = query_ops(make_single_line(N, 'L', 0));\n        widthMeasures.push_back((double)resp.first);\n    }\n\n    // Calibration 2: all in one column, no rotation -> height = sum(h)\n    {\n        auto resp = query_ops(make_single_line(N, 'U', 0));\n        heightMeasures.push_back((double)resp.second);\n    }\n\n    if (calibTurns >= 4) {\n        // Calibration 3: all in one row, rotated -> width = sum(h)\n        {\n            auto resp = query_ops(make_single_line(N, 'L', 1));\n            heightMeasures.push_back((double)resp.first);\n        }\n        // Calibration 4: all in one column, rotated -> height = sum(w)\n        {\n            auto resp = query_ops(make_single_line(N, 'U', 1));\n            widthMeasures.push_back((double)resp.second);\n        }\n    }\n\n    int remainingTurns = T - calibTurns;\n\n    double sumObsW = 0.0, sumObsH = 0.0;\n    for (int i = 0; i < N; i++) {\n        sumObsW += obs[i].w;\n        sumObsH += obs[i].h;\n    }\n\n    auto avg = [](const vector<double>& v) {\n        double s = 0.0;\n        for (double x : v) s += x;\n        return s / v.size();\n    };\n\n    double widthEst = avg(widthMeasures);\n    double heightEst = avg(heightMeasures);\n\n    double tauW = 1.0 / (double)widthMeasures.size();   // variance ratio of averaged aggregate / sigma^2\n    double tauH = 1.0 / (double)heightMeasures.size();\n\n    // Posterior-mean-like additive correction.\n    double dw = (widthEst - sumObsW) / (N + tauW);\n    double dh = (heightEst - sumObsH) / (N + tauH);\n\n    vector<Dim> base(N);\n    for (int i = 0; i < N; i++) {\n        base[i].w = max(1.0, obs[i].w + dw);\n        base[i].h = max(1.0, obs[i].h + dh);\n    }\n\n    if (remainingTurns > 0) {\n        auto pool = generate_pool(base, remainingTurns, sigma, tauW, tauH, rng);\n        if (pool.empty()) {\n            pool.push_back(beam_shelf(base, base, 'L', sqrt(max(1.0, total_area(base))), 200, 1.2));\n        }\n\n        vector<Candidate> chosen;\n        chosen.reserve(remainingTurns);\n\n        int P = (int)pool.size();\n        int cap = min(P, max(remainingTurns, min(P, remainingTurns * 3)));\n        int topTake = min(cap, max(5, remainingTurns * 2 / 3));\n\n        vector<int> order;\n        vector<char> used(P, 0);\n\n        for (int i = 0; i < topTake; i++) {\n            if (!used[i]) {\n                used[i] = 1;\n                order.push_back(i);\n            }\n        }\n\n        int rem = remainingTurns - (int)order.size();\n        if (rem > 0 && cap > topTake) {\n            for (int s = 0; s < rem; s++) {\n                int idx = topTake + (int)((long long)(2 * s + 1) * (cap - topTake) / (2LL * rem));\n                idx = min(idx, cap - 1);\n                if (!used[idx]) {\n                    used[idx] = 1;\n                    order.push_back(idx);\n                }\n            }\n        }\n\n        for (int i = topTake; i < P && (int)order.size() < remainingTurns; i++) {\n            if (!used[i]) {\n                used[i] = 1;\n                order.push_back(i);\n            }\n        }\n\n        while ((int)order.size() < remainingTurns) {\n            order.push_back(order.empty() ? 0 : order[(int)order.size() % max(1, (int)order.size())]);\n        }\n\n        for (int idx : order) chosen.push_back(pool[idx]);\n\n        for (int t = 0; t < remainingTurns; t++) {\n            auto resp = query_ops(chosen[t].ops);\n            (void)resp;\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<int> deg;\n\n    mt19937_64 rng{chrono::steady_clock::now().time_since_epoch().count()};\n    chrono::steady_clock::time_point start_time, deadline;\n\n    struct State {\n        vector<vector<int>> children;\n        vector<vector<int>> comps;\n        vector<int> roots;\n        vector<int> depth, tin, tout, compId;\n        vector<int> subtreeBeauty;\n        vector<int> maxAbsDepth;\n        long long score = 0;\n    };\n\n    struct Move {\n        long long gain = 0;\n        int par = -1;\n        int child = -1;\n        int parentSub = 0;\n        int parDepth = 0;\n        int parentDeg = 0;\n        int childSub = 0;\n    };\n\n    bool time_up() const {\n        return chrono::steady_clock::now() >= deadline;\n    }\n\n    static bool betterMove(const Move& a, const Move& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.parentSub != b.parentSub) return a.parentSub < b.parentSub;\n        if (a.parDepth != b.parDepth) return a.parDepth > b.parDepth;\n        if (a.parentDeg != b.parentDeg) return a.parentDeg > b.parentDeg;\n        if (a.childSub != b.childSub) return a.childSub > b.childSub;\n        if (a.child != b.child) return a.child < b.child;\n        return a.par < b.par;\n    }\n\n    void rebuild(const vector<int>& parent, State& st) {\n        st.children.assign(N, {});\n        st.roots.clear();\n        st.depth.assign(N, 0);\n        st.tin.assign(N, 0);\n        st.tout.assign(N, 0);\n        st.compId.assign(N, -1);\n        st.subtreeBeauty.assign(N, 0);\n        st.maxAbsDepth.assign(N, 0);\n        st.comps.clear();\n        st.score = 1;\n\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] == -1) st.roots.push_back(v);\n            else st.children[parent[v]].push_back(v);\n        }\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v, int comp) -> void {\n            st.compId[v] = comp;\n            st.tin[v] = timer++;\n            st.comps[comp].push_back(v);\n\n            st.subtreeBeauty[v] = A[v];\n            st.maxAbsDepth[v] = st.depth[v];\n            st.score += 1LL * (st.depth[v] + 1) * A[v];\n\n            for (int ch : st.children[v]) {\n                st.depth[ch] = st.depth[v] + 1;\n                self(self, ch, comp);\n                st.subtreeBeauty[v] += st.subtreeBeauty[ch];\n                st.maxAbsDepth[v] = max(st.maxAbsDepth[v], st.maxAbsDepth[ch]);\n            }\n            st.tout[v] = timer;\n        };\n\n        for (int r : st.roots) {\n            st.depth[r] = 0;\n            st.comps.push_back({});\n            dfs(dfs, r, (int)st.comps.size() - 1);\n        }\n    }\n\n    bool makeCandidate(int par, int child, const State& st, Move& mv) {\n        int newDepth = st.depth[par] + 1;\n        if (newDepth > H) return false;\n        if (newDepth <= st.depth[child]) return false;\n\n        // Avoid cycles: par must not be inside subtree(child)\n        if (st.compId[par] == st.compId[child]) {\n            if (st.tin[child] <= st.tin[par] && st.tin[par] < st.tout[child]) {\n                return false;\n            }\n        }\n\n        int delta = newDepth - st.depth[child];\n        if (st.maxAbsDepth[child] + delta > H) return false;\n\n        mv.gain = 1LL * delta * st.subtreeBeauty[child];\n        if (mv.gain <= 0) return false;\n\n        mv.par = par;\n        mv.child = child;\n        mv.parentSub = st.subtreeBeauty[par];\n        mv.parDepth = st.depth[par];\n        mv.parentDeg = deg[par];\n        mv.childSub = st.subtreeBeauty[child];\n        return true;\n    }\n\n    bool findMoveDeterministic(const State& st, Move& best) {\n        bool found = false;\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool findMoveRandomized(const State& st, Move& chosen) {\n        long long bestGain = 0;\n        vector<Move> cand;\n        cand.reserve(64);\n\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain == bestGain) {\n                    cand.push_back(mv);\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain == bestGain) {\n                    cand.push_back(mv);\n                }\n            }\n        }\n\n        if (bestGain <= 0) return false;\n\n        sort(cand.begin(), cand.end(), betterMove);\n        int k = min<int>(8, cand.size());\n        uniform_int_distribution<int> dist(0, k - 1);\n        chosen = cand[dist(rng)];\n        return true;\n    }\n\n    void hillClimb(vector<int>& parent, bool randomized) {\n        while (!time_up()) {\n            State st;\n            rebuild(parent, st);\n\n            Move mv;\n            bool ok = randomized ? findMoveRandomized(st, mv)\n                                 : findMoveDeterministic(st, mv);\n            if (!ok) break;\n\n            parent[mv.child] = mv.par;\n        }\n    }\n\n    bool rerootOptimize(vector<int>& parent) {\n        if (time_up()) return false;\n\n        State st;\n        rebuild(parent, st);\n\n        vector<vector<int>> treeAdj(N);\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] != -1) {\n                treeAdj[v].push_back(parent[v]);\n                treeAdj[parent[v]].push_back(v);\n            }\n        }\n\n        vector<int> newParent = parent;\n\n        for (const auto& comp : st.comps) {\n            if (time_up()) return false;\n            if (comp.size() <= 1) continue;\n\n            long long bestScore = LLONG_MIN;\n            int bestRoot = comp[0];\n\n            auto dfsScore = [&](auto&& self, int v, int p, int d, long long& sc, int& mx) -> void {\n                sc += 1LL * A[v] * d;\n                mx = max(mx, d);\n                for (int to : treeAdj[v]) {\n                    if (to == p) continue;\n                    self(self, to, v, d + 1, sc, mx);\n                }\n            };\n\n            for (int r : comp) {\n                long long sc = 0;\n                int mx = 0;\n                dfsScore(dfsScore, r, -1, 0, sc, mx);\n                if (mx > H) continue;\n\n                bool better = false;\n                if (sc > bestScore) better = true;\n                else if (sc == bestScore) {\n                    if (A[r] < A[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] > deg[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] == deg[bestRoot] && r < bestRoot) better = true;\n                }\n                if (better) {\n                    bestScore = sc;\n                    bestRoot = r;\n                }\n            }\n\n            if (bestScore == LLONG_MIN) continue;\n\n            auto dfsOrient = [&](auto&& self, int v, int p) -> void {\n                newParent[v] = p;\n                for (int to : treeAdj[v]) {\n                    if (to == p) continue;\n                    self(self, to, v);\n                }\n            };\n            dfsOrient(dfsOrient, bestRoot, -1);\n        }\n\n        if (newParent != parent) {\n            parent.swap(newParent);\n            return true;\n        }\n        return false;\n    }\n\n    long long calcScore(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.score;\n    }\n\n    vector<int> runTrial(bool randomized) {\n        vector<int> parent(N, -1);\n\n        for (int phase = 0; phase < 2 && !time_up(); ++phase) {\n            hillClimb(parent, randomized);\n            if (time_up()) break;\n            bool changed = rerootOptimize(parent);\n            if (!changed) break;\n        }\n\n        hillClimb(parent, false); // deterministic polish\n        return parent;\n    }\n\n    vector<int> solve() {\n        start_time = chrono::steady_clock::now();\n        deadline = start_time + chrono::milliseconds(1900);\n\n        vector<int> bestParent(N, -1);\n        long long bestScore = calcScore(bestParent);\n\n        int trial = 0;\n        while (!time_up() && trial < 20) {\n            bool randomized = (trial > 0);\n            vector<int> cand = runTrial(randomized);\n            long long sc = calcScore(cand);\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestParent = cand;\n            }\n            ++trial;\n        }\n\n        // Final deterministic polish from the best solution found.\n        vector<int> polished = bestParent;\n        for (int phase = 0; phase < 2 && !time_up(); ++phase) {\n            hillClimb(polished, false);\n            if (time_up()) break;\n            if (!rerootOptimize(polished)) break;\n        }\n        hillClimb(polished, false);\n        long long finalScore = calcScore(polished);\n        if (finalScore > bestScore) {\n            bestParent = polished;\n            bestScore = finalScore;\n        }\n\n        return bestParent;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M >> solver.H;\n    solver.A.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.A[i];\n\n    solver.edges.resize(solver.M);\n    solver.deg.assign(solver.N, 0);\n    for (int i = 0; i < solver.M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        solver.edges[i] = {u, v};\n        solver.deg[u]++;\n        solver.deg[v]++;\n    }\n\n    // Coordinates are unused in this heuristic, but we must read them.\n    for (int i = 0; i < solver.N; ++i) {\n        int x, y;\n        cin >> x >> y;\n    }\n\n    vector<int> ans = solver.solve();\n\n    for (int i = 0; i < solver.N; ++i) {\n        if (i) cout << ' ';\n        cout << ans[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAX_ONI = 40;\nstatic constexpr int SIDE = 80;   // 20 L + 20 R + 20 U + 20 D\nstatic constexpr int MAXD = 20;\nstatic constexpr double TIME_LIMIT = 1.85;\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 over() const { return elapsed() >= TIME_LIMIT; }\n} timer_;\n\nmt19937_64 rng_(chrono::steady_clock::now().time_since_epoch().count());\n\nint M_ONI;\nvector<pair<int,int>> oni_pos;\n\narray<vector<int>, MAX_ONI> candSides;\narray<array<int, SIDE>, MAX_ONI> depthOf;\narray<int, MAX_ONI> candCnt;\narray<int, MAX_ONI> minDepthArr;\n\ninline int sideL(int r) { return r; }\ninline int sideR(int r) { return 20 + r; }\ninline int sideU(int c) { return 40 + c; }\ninline int sideD(int c) { return 60 + c; }\n\ninline char sideDir(int s) {\n    if (s < 20) return 'L';\n    if (s < 40) return 'R';\n    if (s < 60) return 'U';\n    return 'D';\n}\ninline int sideIdx(int s) {\n    if (s < 20) return s;\n    if (s < 40) return s - 20;\n    if (s < 60) return s - 40;\n    return s - 60;\n}\ninline char revDir(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\nstruct State {\n    array<int, MAX_ONI> assign;                         // side id\n    array<array<unsigned char, MAXD + 1>, SIDE> cnt;   // cnt[side][depth]\n    array<int, SIDE> dep;                              // max depth on side\n    array<unsigned long long, SIDE> mem;               // assigned oni bitmask\n    int S = 0;                                         // sum 2*dep\n    int M = 0;                                         // max dep\n    int cost() const { return S - M; }\n};\n\ninline int recomputeM(const State& st) {\n    int m = 0;\n    for (int s = 0; s < SIDE; s++) m = max(m, st.dep[s]);\n    return m;\n}\n\nState emptyState() {\n    State st;\n    st.assign.fill(-1);\n    for (int s = 0; s < SIDE; s++) {\n        st.cnt[s].fill(0);\n        st.dep[s] = 0;\n        st.mem[s] = 0ULL;\n    }\n    st.S = 0;\n    st.M = 0;\n    return st;\n}\n\ninline int popcount_ull(unsigned long long x) {\n    return __builtin_popcountll(x);\n}\n\nvector<int> membersOfMask(unsigned long long mask) {\n    vector<int> res;\n    while (mask) {\n        int b = __builtin_ctzll(mask);\n        res.push_back(b);\n        mask &= mask - 1;\n    }\n    return res;\n}\n\nvoid removeAssign(State& st, int u) {\n    int s = st.assign[u];\n    if (s < 0) return;\n    int d = depthOf[u][s];\n    st.assign[u] = -1;\n    st.mem[s] &= ~(1ULL << u);\n    st.cnt[s][d]--;\n\n    if (d == st.dep[s] && st.cnt[s][d] == 0) {\n        int nd = st.dep[s];\n        while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n        st.S += 2 * (nd - st.dep[s]);\n        st.dep[s] = nd;\n    }\n    st.M = recomputeM(st);\n}\n\nvoid addAssign(State& st, int u, int s) {\n    int d = depthOf[u][s];\n    st.assign[u] = s;\n    st.mem[s] |= (1ULL << u);\n    st.cnt[s][d]++;\n    if (d > st.dep[s]) {\n        st.S += 2 * (d - st.dep[s]);\n        st.dep[s] = d;\n    }\n    if (st.dep[s] > st.M) st.M = st.dep[s];\n}\n\ninline int secondDepthAfterRemoving(const State& st, int s, int remDepth) {\n    if (remDepth != st.dep[s]) return st.dep[s];\n    if (st.cnt[s][remDepth] >= 2) return st.dep[s];\n    int nd = st.dep[s] - 1;\n    while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n    return nd;\n}\n\nint evalAdd(const State& st, int u, int s) {\n    int d = depthOf[u][s];\n    int nd = max(st.dep[s], d);\n    int newS = st.S + 2 * (nd - st.dep[s]);\n    int newM = max(st.M, nd);\n    return newS - newM;\n}\n\nint evalMove(const State& st, int u, int ns) {\n    int os = st.assign[u];\n    if (os == ns) return st.cost();\n\n    int od = depthOf[u][os];\n    int nd = depthOf[u][ns];\n\n    int depOldAfter = secondDepthAfterRemoving(st, os, od);\n    int depNewAfter = max(st.dep[ns], nd);\n\n    int newS = st.S + 2 * (depOldAfter - st.dep[os]) + 2 * (depNewAfter - st.dep[ns]);\n\n    int newM = 0;\n    for (int s = 0; s < SIDE; s++) {\n        int d = st.dep[s];\n        if (s == os) d = depOldAfter;\n        else if (s == ns) d = depNewAfter;\n        newM = max(newM, d);\n    }\n    return newS - newM;\n}\n\nvector<int> makeOrderDifficulty(bool randomized) {\n    vector<int> ord(M_ONI);\n    iota(ord.begin(), ord.end(), 0);\n\n    vector<uint64_t> key(M_ONI);\n    for (int i = 0; i < M_ONI; i++) key[i] = rng_();\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (candCnt[a] != candCnt[b]) return candCnt[a] < candCnt[b];\n        if (minDepthArr[a] != minDepthArr[b]) return minDepthArr[a] > minDepthArr[b];\n        if (randomized) return key[a] < key[b];\n        return a < b;\n    });\n    return ord;\n}\n\nvector<int> makeOrderRandom() {\n    vector<int> ord(M_ONI);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng_);\n    return ord;\n}\n\nState buildGreedy(const vector<int>& ord, bool randomized) {\n    State st = emptyState();\n\n    for (int u : ord) {\n        vector<pair<int,int>> opts;\n        opts.reserve(candSides[u].size());\n        for (int s : candSides[u]) {\n            opts.push_back({evalAdd(st, u, s), s});\n        }\n        sort(opts.begin(), opts.end());\n\n        int chooseSide = opts[0].second;\n        if (randomized) {\n            int slack = 1;\n            int lim = 1;\n            while (lim < (int)opts.size() && opts[lim].first <= opts[0].first + slack) ++lim;\n            lim = min(lim, 3);\n            chooseSide = opts[(int)(rng_() % lim)].second;\n        }\n        addAssign(st, u, chooseSide);\n    }\n    return st;\n}\n\nState buildMinDepthState() {\n    State st = emptyState();\n    for (int u = 0; u < M_ONI; u++) {\n        int bestS = candSides[u][0];\n        int bestD = depthOf[u][bestS];\n        for (int s : candSides[u]) {\n            int d = depthOf[u][s];\n            if (d < bestD || (d == bestD && s < bestS)) {\n                bestD = d;\n                bestS = s;\n            }\n        }\n        addAssign(st, u, bestS);\n    }\n    return st;\n}\n\nbool exactReoptSubset(State& st, vector<int> subset, int forbidSide = -1) {\n    if (subset.empty()) return false;\n\n    State original = st;\n    for (int u : subset) removeAssign(st, u);\n\n    for (int u : subset) {\n        int ok = 0;\n        for (int s : candSides[u]) if (s != forbidSide) ok++;\n        if (ok == 0) {\n            st = original;\n            return false;\n        }\n    }\n\n    sort(subset.begin(), subset.end(), [&](int a, int b) {\n        int ca = 0, cb = 0;\n        for (int s : candSides[a]) if (s != forbidSide) ca++;\n        for (int s : candSides[b]) if (s != forbidSide) cb++;\n        if (ca != cb) return ca < cb;\n        return minDepthArr[a] > minDepthArr[b];\n    });\n\n    int bestCost = original.cost();\n    State bestState = original;\n    long long nodes = 0;\n    bool timeout = false;\n\n    function<void(int)> dfs = [&](int idx) {\n        if ((nodes++ & 1023LL) == 0 && timer_.over()) {\n            timeout = true;\n            return;\n        }\n        int curCost = st.cost();\n        if (curCost >= bestCost) return;\n        if (idx == (int)subset.size()) {\n            bestCost = curCost;\n            bestState = st;\n            return;\n        }\n\n        int u = subset[idx];\n        vector<pair<int,int>> opts;\n        opts.reserve(candSides[u].size());\n        for (int s : candSides[u]) {\n            if (s == forbidSide) continue;\n            int c = evalAdd(st, u, s);\n            if (c < bestCost) opts.push_back({c, s});\n        }\n        sort(opts.begin(), opts.end());\n\n        for (auto [c, s] : opts) {\n            if (c >= bestCost) break;\n            addAssign(st, u, s);\n            dfs(idx + 1);\n            removeAssign(st, u);\n            if (timeout) return;\n        }\n    };\n\n    dfs(0);\n    st = bestState;\n    return st.cost() < original.cost();\n}\n\nbool exactCloseOneSide(State& st, int side) {\n    int sz = popcount_ull(st.mem[side]);\n    if (sz <= 1 || sz > 8) return false;\n    auto subset = membersOfMask(st.mem[side]);\n    for (int u : subset) {\n        bool hasAlt = false;\n        for (int s : candSides[u]) {\n            if (s != side) { hasAlt = true; break; }\n        }\n        if (!hasAlt) return false;\n    }\n    return exactReoptSubset(st, subset, side);\n}\n\nvoid localImprove(State& st) {\n    while (!timer_.over()) {\n        bool improved = false;\n\n        vector<int> ord(M_ONI);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng_);\n\n        for (int u : ord) {\n            if (timer_.over()) return;\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n\n            for (int s : candSides[u]) {\n                if (s == curS) continue;\n                int c = evalMove(st, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, u);\n                addAssign(st, u, bestS);\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        vector<int> sideOrd;\n        for (int s = 0; s < SIDE; s++) {\n            int sz = popcount_ull(st.mem[s]);\n            if (sz >= 2 && sz <= 8) sideOrd.push_back(s);\n        }\n        shuffle(sideOrd.begin(), sideOrd.end(), rng_);\n\n        for (int s : sideOrd) {\n            if (timer_.over()) return;\n            if (exactCloseOneSide(st, s)) {\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvector<int> chooseSubset(const State& st) {\n    vector<int> usedSides;\n    for (int s = 0; s < SIDE; s++) {\n        int sz = popcount_ull(st.mem[s]);\n        if (sz >= 2) usedSides.push_back(s);\n    }\n\n    int mode = (int)(rng_() % 3);\n    vector<int> subset;\n\n    if (mode == 0 && !usedSides.empty()) {\n        int s = usedSides[(int)(rng_() % usedSides.size())];\n        subset = membersOfMask(st.mem[s]);\n        shuffle(subset.begin(), subset.end(), rng_);\n        if ((int)subset.size() > 8) subset.resize(8);\n        return subset;\n    }\n\n    if (mode == 1 && usedSides.size() >= 2) {\n        for (int rep = 0; rep < 12; rep++) {\n            int s1 = usedSides[(int)(rng_() % usedSides.size())];\n            int s2 = usedSides[(int)(rng_() % usedSides.size())];\n            if (s1 == s2) continue;\n            vector<int> a = membersOfMask(st.mem[s1]);\n            vector<int> b = membersOfMask(st.mem[s2]);\n            vector<int> all = a;\n            for (int x : b) all.push_back(x);\n            sort(all.begin(), all.end());\n            all.erase(unique(all.begin(), all.end()), all.end());\n            shuffle(all.begin(), all.end(), rng_);\n            if ((int)all.size() > 8) all.resize(8);\n            if ((int)all.size() >= 2) return all;\n        }\n    }\n\n    int k = min(M_ONI, 4 + (int)(rng_() % 4)); // 4..7\n    vector<int> ord(M_ONI);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng_);\n    ord.resize(k);\n    return ord;\n}\n\nvoid emitSide(vector<pair<char,int>>& ops, int side, int depth, bool restore) {\n    char d = sideDir(side);\n    char rd = revDir(d);\n    int p = sideIdx(side);\n    for (int t = 0; t < depth; t++) ops.push_back({d, p});\n    if (restore) {\n        for (int t = 0; t < depth; t++) ops.push_back({rd, p});\n    }\n}\n\nvector<pair<char,int>> buildOpsFromState(const State& st) {\n    vector<int> used;\n    for (int s = 0; s < SIDE; s++) if (st.dep[s] > 0) used.push_back(s);\n    vector<pair<char,int>> ops;\n    if (used.empty()) return ops;\n\n    int finalSide = used[0];\n    for (int s : used) {\n        if (st.dep[s] > st.dep[finalSide]) finalSide = s;\n    }\n\n    sort(used.begin(), used.end(), [&](int a, int b) {\n        if (st.dep[a] != st.dep[b]) return st.dep[a] < st.dep[b];\n        return a < b;\n    });\n\n    for (int s : used) {\n        if (s == finalSide) continue;\n        emitSide(ops, s, st.dep[s], true);\n    }\n    emitSide(ops, finalSide, st.dep[finalSide], false);\n    return ops;\n}\n\nvector<pair<char,int>> buildTrivialOps() {\n    vector<int> chooseS(M_ONI), chooseD(M_ONI);\n    for (int u = 0; u < M_ONI; u++) {\n        int bestS = candSides[u][0];\n        int bestD = depthOf[u][bestS];\n        for (int s : candSides[u]) {\n            int d = depthOf[u][s];\n            if (d < bestD || (d == bestD && s < bestS)) {\n                bestD = d;\n                bestS = s;\n            }\n        }\n        chooseS[u] = bestS;\n        chooseD[u] = bestD;\n    }\n\n    int last = 0;\n    for (int u = 1; u < M_ONI; u++) {\n        if (chooseD[u] > chooseD[last]) last = u;\n    }\n\n    vector<pair<char,int>> ops;\n    for (int u = 0; u < M_ONI; u++) {\n        if (u == last) continue;\n        emitSide(ops, chooseS[u], chooseD[u], true);\n    }\n    emitSide(ops, chooseS[last], chooseD[last], false);\n    return ops;\n}\n\npair<int,int> simulateOps(vector<string> board, const vector<pair<char,int>>& ops) {\n    int removedO = 0;\n    for (auto [d, p] : ops) {\n        if (d == 'L') {\n            if (board[p][0] == 'o') removedO++;\n            for (int j = 0; j + 1 < N; j++) board[p][j] = board[p][j+1];\n            board[p][N-1] = '.';\n        } else if (d == 'R') {\n            if (board[p][N-1] == 'o') removedO++;\n            for (int j = N-1; j >= 1; j--) board[p][j] = board[p][j-1];\n            board[p][0] = '.';\n        } else if (d == 'U') {\n            if (board[0][p] == 'o') removedO++;\n            for (int i = 0; i + 1 < N; i++) board[i][p] = board[i+1][p];\n            board[N-1][p] = '.';\n        } else if (d == 'D') {\n            if (board[N-1][p] == 'o') removedO++;\n            for (int i = N-1; i >= 1; i--) board[i][p] = board[i-1][p];\n            board[0][p] = '.';\n        }\n    }\n\n    int remainX = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (board[i][j] == 'x') remainX++;\n        }\n    }\n    return {remainX, removedO};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n_in;\n    cin >> n_in;\n    vector<string> board(N);\n    for (int i = 0; i < N; i++) cin >> board[i];\n\n    oni_pos.clear();\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (board[i][j] == 'x') oni_pos.push_back({i, j});\n        }\n    }\n    M_ONI = (int)oni_pos.size();\n\n    for (int u = 0; u < MAX_ONI; u++) {\n        candSides[u].clear();\n        depthOf[u].fill(-1);\n        candCnt[u] = 0;\n        minDepthArr[u] = 1e9;\n    }\n\n    array<int, N> firstORow, lastORow, firstOCol, lastOCol;\n    for (int i = 0; i < N; i++) {\n        firstORow[i] = N;\n        lastORow[i] = -1;\n        for (int j = 0; j < N; j++) {\n            if (board[i][j] == 'o') {\n                firstORow[i] = min(firstORow[i], j);\n                lastORow[i] = max(lastORow[i], j);\n            }\n        }\n    }\n    for (int j = 0; j < N; j++) {\n        firstOCol[j] = N;\n        lastOCol[j] = -1;\n        for (int i = 0; i < N; i++) {\n            if (board[i][j] == 'o') {\n                firstOCol[j] = min(firstOCol[j], i);\n                lastOCol[j] = max(lastOCol[j], i);\n            }\n        }\n    }\n\n    for (int u = 0; u < M_ONI; u++) {\n        auto [r, c] = oni_pos[u];\n\n        if (c < firstORow[r]) {\n            int s = sideL(r), d = c + 1;\n            candSides[u].push_back(s);\n            depthOf[u][s] = d;\n            minDepthArr[u] = min(minDepthArr[u], d);\n        }\n        if (c > lastORow[r]) {\n            int s = sideR(r), d = N - c;\n            candSides[u].push_back(s);\n            depthOf[u][s] = d;\n            minDepthArr[u] = min(minDepthArr[u], d);\n        }\n        if (r < firstOCol[c]) {\n            int s = sideU(c), d = r + 1;\n            candSides[u].push_back(s);\n            depthOf[u][s] = d;\n            minDepthArr[u] = min(minDepthArr[u], d);\n        }\n        if (r > lastOCol[c]) {\n            int s = sideD(c), d = N - r;\n            candSides[u].push_back(s);\n            depthOf[u][s] = d;\n            minDepthArr[u] = min(minDepthArr[u], d);\n        }\n\n        candCnt[u] = (int)candSides[u].size();\n        if (candCnt[u] == 0) {\n            // Constraint says this never happens, but keep a safety net.\n            // Fallback: assign impossible large value (should not be used).\n            minDepthArr[u] = 1000;\n        }\n    }\n\n    State best = buildMinDepthState();\n    localImprove(best);\n\n    {\n        State st = buildGreedy(makeOrderDifficulty(false), false);\n        localImprove(st);\n        if (st.cost() < best.cost()) best = st;\n    }\n    {\n        State st = buildGreedy(makeOrderDifficulty(true), true);\n        localImprove(st);\n        if (st.cost() < best.cost()) best = st;\n    }\n\n    int iter = 0;\n    while (!timer_.over()) {\n        State st;\n        if (iter < 20 || (rng_() % 100) < 30) {\n            if ((rng_() & 1) == 0) st = buildGreedy(makeOrderRandom(), true);\n            else st = buildGreedy(makeOrderDifficulty(true), true);\n            localImprove(st);\n        } else {\n            st = best;\n            auto subset = chooseSubset(st);\n            exactReoptSubset(st, subset, -1);\n            localImprove(st);\n        }\n        if (st.cost() < best.cost()) best = st;\n        iter++;\n    }\n\n    vector<pair<char,int>> ans = buildOpsFromState(best);\n    auto [rx, ry] = simulateOps(board, ans);\n\n    vector<pair<char,int>> trivial = buildTrivialOps();\n    auto [tx, ty] = simulateOps(board, trivial);\n\n    bool okAns = ((int)ans.size() <= 4 * N * N && rx == 0 && ry == 0);\n    bool okTrivial = ((int)trivial.size() <= 4 * N * N && tx == 0 && ty == 0);\n\n    vector<pair<char,int>> out;\n    if (okAns && (!okTrivial || ans.size() <= trivial.size())) out = ans;\n    else if (okTrivial) out = trivial;\n    else out = ans; // Should never happen.\n\n    for (auto [d, p] : out) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct SimResult {\n    vector<int> cnt;\n    int end_node;\n    ll err;\n};\n\nstruct BuildResult {\n    vector<int> a, b;\n    ll approx_cost;\n};\n\nint N, Lw;\nvector<int> T;\n\n// ---------- utility ----------\nstatic inline ll absll(ll x) { return x >= 0 ? x : -x; }\n\nvector<int> next_from_order(const vector<int>& order) {\n    vector<int> nxt(N);\n    for (int i = 0; i < N; ++i) nxt[order[i]] = order[(i + 1) % N];\n    return nxt;\n}\n\nvector<int> prev_from_order(const vector<int>& order) {\n    vector<int> prv(N);\n    for (int i = 0; i < N; ++i) prv[order[(i + 1) % N]] = order[i];\n    return prv;\n}\n\nll calc_cost(const vector<int>& assign, const vector<int>& item, const vector<int>& need, vector<int>* load_out = nullptr) {\n    vector<int> load(N, 0);\n    for (int i = 0; i < N; ++i) load[assign[i]] += item[i];\n    ll cost = 0;\n    for (int j = 0; j < N; ++j) cost += absll((ll)load[j] - need[j]);\n    if (load_out) *load_out = load;\n    return cost;\n}\n\n// ---------- initial assignment 1: DP on sorted items / sorted needs ----------\nvector<int> init_dp_partition(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N), tgt_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    iota(tgt_ord.begin(), tgt_ord.end(), 0);\n\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] < item[b];\n        return a < b;\n    });\n    sort(tgt_ord.begin(), tgt_ord.end(), [&](int a, int b) {\n        if (need[a] != need[b]) return need[a] < need[b];\n        return a < b;\n    });\n\n    vector<ll> pref(N + 1, 0);\n    for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + item[src_ord[i]];\n\n    const ll INF = (1LL << 60);\n    vector<vector<ll>> dp(N + 1, vector<ll>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int k = 0; k < N; ++k) {\n        for (int i = 0; i <= N; ++i) {\n            if (dp[k][i] >= INF) continue;\n            for (int j = i; j <= N; ++j) {\n                ll segsum = pref[j] - pref[i];\n                ll nd = dp[k][i] + absll(segsum - (ll)need[tgt_ord[k]]);\n                if (nd < dp[k + 1][j]) {\n                    dp[k + 1][j] = nd;\n                    par[k + 1][j] = i;\n                }\n            }\n        }\n    }\n\n    vector<int> assign(N, 0);\n    int cur = N;\n    for (int k = N - 1; k >= 0; --k) {\n        int prv = par[k + 1][cur];\n        if (prv < 0) prv = 0;\n        for (int p = prv; p < cur; ++p) {\n            assign[src_ord[p]] = tgt_ord[k];\n        }\n        cur = prv;\n    }\n    return assign;\n}\n\n// ---------- initial assignment 2: greedy best-fit ----------\nvector<int> init_greedy(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] > item[b];\n        return a < b;\n    });\n\n    vector<int> assign(N, 0);\n    vector<int> load(N, 0);\n\n    for (int s : src_ord) {\n        ll best_delta = (1LL << 60);\n        int best_t = 0;\n        for (int t = 0; t < N; ++t) {\n            ll before = absll((ll)load[t] - need[t]);\n            ll after = absll((ll)load[t] + item[s] - need[t]);\n            ll delta = after - before;\n            ll deficit = (ll)need[t] - load[t];\n            ll best_deficit = (ll)need[best_t] - load[best_t];\n            if (delta < best_delta ||\n                (delta == best_delta && deficit > best_deficit) ||\n                (delta == best_delta && deficit == best_deficit && t < best_t)) {\n                best_delta = delta;\n                best_t = t;\n            }\n        }\n        assign[s] = best_t;\n        load[best_t] += item[s];\n    }\n    return assign;\n}\n\n// ---------- local improvement: moves + swaps ----------\nll local_search_assign(vector<int>& assign, const vector<int>& item, const vector<int>& need) {\n    vector<int> load;\n    ll total = calc_cost(assign, item, need, &load);\n\n    const int MAX_IT = 140;\n    for (int iter = 0; iter < MAX_IT; ++iter) {\n        vector<ll> base(N);\n        for (int j = 0; j < N; ++j) base[j] = absll((ll)load[j] - need[j]);\n\n        ll best_delta = 0;\n        int best_kind = 0; // 1=move, 2=swap\n        int bi = -1, bj = -1, bk = -1;\n\n        // moves\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i];\n            int w = item[i];\n            if (w == 0) continue;\n            for (int v = 0; v < N; ++v) if (v != u) {\n                ll delta = 0;\n                delta += absll((ll)load[u] - w - need[u]) - base[u];\n                delta += absll((ll)load[v] + w - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 1;\n                    bi = i; bj = v;\n                }\n            }\n        }\n\n        // swaps\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i];\n            int wi = item[i];\n            for (int k = i + 1; k < N; ++k) {\n                int v = assign[k];\n                if (u == v) continue;\n                int wk = item[k];\n                ll delta = 0;\n                delta += absll((ll)load[u] - wi + wk - need[u]) - base[u];\n                delta += absll((ll)load[v] - wk + wi - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 2;\n                    bi = i; bk = k;\n                }\n            }\n        }\n\n        if (best_kind == 0) break;\n\n        if (best_kind == 1) {\n            int i = bi, v = bj;\n            int u = assign[i];\n            int w = item[i];\n            load[u] -= w;\n            load[v] += w;\n            assign[i] = v;\n            total += best_delta;\n        } else {\n            int i = bi, k = bk;\n            int u = assign[i], v = assign[k];\n            int wi = item[i], wk = item[k];\n            load[u] = load[u] - wi + wk;\n            load[v] = load[v] - wk + wi;\n            swap(assign[i], assign[k]);\n            total += best_delta;\n        }\n    }\n\n    return total;\n}\n\n// ---------- build graph from a fixed cycle order ----------\nBuildResult build_graph(const vector<int>& order, const vector<int>& est_cnt, bool exact_end, int end_node) {\n    vector<int> nxt = next_from_order(order);\n    vector<int> prv = prev_from_order(order);\n\n    vector<int> out = est_cnt;\n    if (exact_end && 0 <= end_node && end_node < N) out[end_node]--;\n\n    vector<int> fixed_a(N), item_b(N), need(N);\n    for (int i = 0; i < N; ++i) {\n        if (out[i] < 0) out[i] = 0;\n        fixed_a[i] = (out[i] + 1) / 2; // odd departures -> a_i\n        item_b[i] = out[i] / 2;        // even departures -> b_i\n    }\n    for (int j = 0; j < N; ++j) {\n        need[j] = T[j] - (j == 0 ? 1 : 0) - fixed_a[prv[j]];\n    }\n\n    vector<int> assign1 = init_dp_partition(item_b, need);\n    ll cost1 = local_search_assign(assign1, item_b, need);\n\n    vector<int> assign2 = init_greedy(item_b, need);\n    ll cost2 = local_search_assign(assign2, item_b, need);\n\n    vector<int> best_assign;\n    ll best_cost;\n    if (cost1 <= cost2) {\n        best_assign = move(assign1);\n        best_cost = cost1;\n    } else {\n        best_assign = move(assign2);\n        best_cost = cost2;\n    }\n\n    BuildResult res;\n    res.a = move(nxt);\n    res.b = move(best_assign);\n    res.approx_cost = best_cost;\n    return res;\n}\n\n// ---------- exact simulation ----------\nSimResult simulate_graph(const vector<int>& a, const vector<int>& b) {\n    vector<int> cnt(N, 0);\n    int cur = 0;\n    int end_node = 0;\n\n    for (int week = 0; week < Lw; ++week) {\n        ++cnt[cur];\n        end_node = cur;\n        if (week + 1 == Lw) break;\n        cur = (cnt[cur] & 1) ? a[cur] : b[cur];\n    }\n\n    ll err = 0;\n    for (int i = 0; i < N; ++i) err += absll((ll)cnt[i] - T[i]);\n\n    return {cnt, end_node, err};\n}\n\n// ---------- cycle order generators ----------\nvector<int> sorted_order(bool desc) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return desc ? (T[a] > T[b]) : (T[a] < T[b]);\n        return a < b;\n    });\n    return ord;\n}\n\nvector<int> nearest_neighbor_order(int start, bool half_cost_mode) {\n    vector<int> ord;\n    vector<int> used(N, 0);\n    ord.reserve(N);\n    ord.push_back(start);\n    used[start] = 1;\n    int cur = start;\n\n    for (int step = 1; step < N; ++step) {\n        int best = -1;\n        ll best1 = (1LL << 60), best2 = (1LL << 60);\n\n        for (int v = 0; v < N; ++v) if (!used[v]) {\n            ll c1, c2;\n            if (!half_cost_mode) {\n                c1 = absll((ll)T[cur] - T[v]);\n                c2 = 0;\n            } else {\n                c1 = max(0, (T[cur] + 1) / 2 - T[v]); // avoid too-large predecessor contribution\n                c2 = absll((ll)T[cur] - T[v]);\n            }\n            if (best == -1 || c1 < best1 || (c1 == best1 && c2 < best2) || (c1 == best1 && c2 == best2 && v < best)) {\n                best = v;\n                best1 = c1;\n                best2 = c2;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return ord;\n}\n\nvector<int> median_out_order(const vector<int>& base_sorted) {\n    vector<int> ord;\n    ord.reserve(N);\n    int mid = N / 2;\n    ord.push_back(base_sorted[mid]);\n    for (int d = 1; (int)ord.size() < N; ++d) {\n        if (mid - d >= 0) ord.push_back(base_sorted[mid - d]);\n        if ((int)ord.size() >= N) break;\n        if (mid + d < N) ord.push_back(base_sorted[mid + d]);\n    }\n    return ord;\n}\n\nvector<int> alternating_low_high_order() {\n    vector<int> s = sorted_order(false);\n    vector<int> ord;\n    ord.reserve(N);\n    int l = 0, r = N - 1;\n    while (l <= r) {\n        ord.push_back(s[l++]);\n        if (l <= r) ord.push_back(s[r--]);\n    }\n    return ord;\n}\n\nvoid add_order_if_new(vector<vector<int>>& orders, set<vector<int>>& seen_next, const vector<int>& ord) {\n    vector<int> nxt = next_from_order(ord);\n    if (seen_next.insert(nxt).second) {\n        orders.push_back(ord);\n    }\n}\n\n// ---------- candidate ----------\nstruct Candidate {\n    vector<int> order;\n    vector<int> a, b;\n    vector<int> cnt;\n    int end_node;\n    ll err;\n    ll approx_cost;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> Lw;\n    T.resize(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    vector<vector<int>> orders;\n    set<vector<int>> seen_next;\n\n    vector<int> desc = sorted_order(true);\n    vector<int> asc = sorted_order(false);\n    vector<int> orig(N), revorig(N);\n    iota(orig.begin(), orig.end(), 0);\n    revorig = orig;\n    reverse(revorig.begin(), revorig.end());\n\n    add_order_if_new(orders, seen_next, desc);\n    add_order_if_new(orders, seen_next, asc);\n    add_order_if_new(orders, seen_next, orig);\n    add_order_if_new(orders, seen_next, revorig);\n    add_order_if_new(orders, seen_next, nearest_neighbor_order(0, false));\n    add_order_if_new(orders, seen_next, nearest_neighbor_order(0, true));\n\n    int imin = min_element(T.begin(), T.end()) - T.begin();\n    int imax = max_element(T.begin(), T.end()) - T.begin();\n    add_order_if_new(orders, seen_next, nearest_neighbor_order(imin, false));\n    add_order_if_new(orders, seen_next, nearest_neighbor_order(imax, false));\n    add_order_if_new(orders, seen_next, nearest_neighbor_order(imax, true));\n\n    add_order_if_new(orders, seen_next, median_out_order(desc));\n    {\n        auto tmp = median_out_order(desc);\n        reverse(tmp.begin(), tmp.end());\n        add_order_if_new(orders, seen_next, tmp);\n    }\n    add_order_if_new(orders, seen_next, alternating_low_high_order());\n    {\n        auto tmp = alternating_low_high_order();\n        reverse(tmp.begin(), tmp.end());\n        add_order_if_new(orders, seen_next, tmp);\n    }\n\n    // A few random perturbations around descending / ascending\n    mt19937 rng(123456789);\n    for (int rep = 0; rep < 4; ++rep) {\n        auto tmp = desc;\n        for (int k = 0; k < 6; ++k) {\n            if (rng() & 1) {\n                int x = rng() % N;\n                int y = rng() % N;\n                swap(tmp[x], tmp[y]);\n            } else {\n                int l = rng() % N;\n                int len = 2 + (rng() % 7);\n                int r = min(N, l + len);\n                reverse(tmp.begin() + l, tmp.begin() + r);\n            }\n        }\n        add_order_if_new(orders, seen_next, tmp);\n    }\n    for (int rep = 0; rep < 4; ++rep) {\n        auto tmp = asc;\n        for (int k = 0; k < 6; ++k) {\n            if (rng() & 1) {\n                int x = rng() % N;\n                int y = rng() % N;\n                swap(tmp[x], tmp[y]);\n            } else {\n                int l = rng() % N;\n                int len = 2 + (rng() % 7);\n                int r = min(N, l + len);\n                reverse(tmp.begin() + l, tmp.begin() + r);\n            }\n        }\n        add_order_if_new(orders, seen_next, tmp);\n    }\n\n    vector<Candidate> cand_list;\n    cand_list.reserve(orders.size());\n\n    // Initial candidates from T\n    for (const auto& ord : orders) {\n        BuildResult br = build_graph(ord, T, false, -1);\n        SimResult sr = simulate_graph(br.a, br.b);\n        cand_list.push_back({ord, br.a, br.b, sr.cnt, sr.end_node, sr.err, br.approx_cost});\n    }\n\n    sort(cand_list.begin(), cand_list.end(), [&](const Candidate& x, const Candidate& y) {\n        if (x.err != y.err) return x.err < y.err;\n        return x.approx_cost < y.approx_cost;\n    });\n\n    Candidate best = cand_list[0];\n\n    // Refine best few using observed counts\n    int topK = min<int>(4, cand_list.size());\n    for (int idx = 0; idx < topK; ++idx) {\n        Candidate cur = cand_list[idx];\n        for (int it = 0; it < 2; ++it) {\n            BuildResult br = build_graph(cur.order, cur.cnt, true, cur.end_node);\n            SimResult sr = simulate_graph(br.a, br.b);\n            Candidate nxtcand{cur.order, br.a, br.b, sr.cnt, sr.end_node, sr.err, br.approx_cost};\n            if (nxtcand.err < cur.err) {\n                cur = move(nxtcand);\n                if (cur.err < best.err || (cur.err == best.err && cur.approx_cost < best.approx_cost)) {\n                    best = cur;\n                }\n            } else {\n                break;\n            }\n        }\n        if (cur.err < best.err || (cur.err == best.err && cur.approx_cost < best.approx_cost)) {\n            best = cur;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << best.a[i] << ' ' << best.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 800;\nstatic constexpr double INF = 1e100;\n\nint N, M, Q, L, Wv;\nvector<int> G;\nstatic int SX[MAXN], SY[MAXN];          // doubled centers\nstatic uint64_t KEY_[MAXN];             // Morton key\nstatic double distMat[MAXN][MAXN];\n\nstruct GroupItem {\n    int size;\n    int id;\n};\n\nstruct Plan {\n    vector<int> order;   // order of cities in the group\n    vector<int> adds;    // each block adds t new cities; block size = t + 1\n    double estCost = 0.0;\n};\n\nuint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\n\nuint64_t mortonEncode(uint32_t x, uint32_t y) {\n    return (uint64_t)part1by1(x) | ((uint64_t)part1by1(y) << 1);\n}\n\nbool cmpMortonCity(int a, int b) {\n    if (KEY_[a] != KEY_[b]) return KEY_[a] < KEY_[b];\n    return a < b;\n}\nbool cmpXCity(int a, int b) {\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    return a < b;\n}\nbool cmpYCity(int a, int b) {\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\n\ndouble mst_cost_slice(const vector<int>& ord, int st, int len) {\n    if (len <= 1) return 0.0;\n    double md[16];\n    bool used[16];\n    for (int i = 0; i < len; i++) {\n        md[i] = INF;\n        used[i] = false;\n    }\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < len; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < len; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = true;\n        total += bv;\n        int u = ord[st + bi];\n        for (int j = 0; j < len; j++) {\n            if (!used[j]) {\n                double w = distMat[u][ord[st + j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\ndouble optimize_chain_cost_only(const vector<int>& ord) {\n    int g = (int)ord.size();\n    if (g <= 1) return 0.0;\n    if (g == 2) return distMat[ord[0]][ord[1]];\n    if (g <= L) return mst_cost_slice(ord, 0, g);\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);  // minimal number of blocks\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = distMat[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<double> dp(remain + 1, INF), ndp(remain + 1, INF);\n    dp[0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        fill(ndp.begin(), ndp.end(), INF);\n        for (int p = 0; p <= remain; p++) {\n            if (dp[p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[p] + wcost[p][t];\n                if (cand < ndp[np]) ndp[np] = cand;\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    return dp[remain];\n}\n\npair<double, vector<int>> optimize_chain_reconstruct(const vector<int>& ord) {\n    int g = (int)ord.size();\n    if (g <= 1) return {0.0, {}};\n    if (g == 2) return {distMat[ord[0]][ord[1]], {}};\n    if (g <= L) return {mst_cost_slice(ord, 0, g), {}};\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = distMat[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<vector<double>> dp(K + 1, vector<double>(remain + 1, INF));\n    vector<vector<int>> par(K + 1, vector<int>(remain + 1, -1));\n    dp[0][0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        for (int p = 0; p <= remain; p++) {\n            if (dp[b][p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[b][p] + wcost[p][t];\n                if (cand < dp[b + 1][np]) {\n                    dp[b + 1][np] = cand;\n                    par[b + 1][np] = t;\n                }\n            }\n        }\n    }\n\n    vector<int> adds;\n    int p = remain;\n    for (int b = K; b >= 1; b--) {\n        int t = par[b][p];\n        if (t < 0) break;\n        adds.push_back(t);\n        p -= t;\n    }\n    reverse(adds.begin(), adds.end());\n    return {dp[K][remain], adds};\n}\n\nvector<int> sort_morton(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpMortonCity);\n    return v;\n}\nvector<int> sort_x(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpXCity);\n    return v;\n}\nvector<int> sort_y(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpYCity);\n    return v;\n}\n\nvector<int> nn_order(const vector<int>& group, int startCity) {\n    int g = (int)group.size();\n    vector<char> used(N, 0);\n    vector<int> ord;\n    ord.reserve(g);\n    int cur = startCity;\n    used[cur] = 1;\n    ord.push_back(cur);\n\n    for (int step = 1; step < g; step++) {\n        int best = -1;\n        double bestD = INF;\n        for (int v : group) {\n            if (used[v]) continue;\n            double d = distMat[cur][v];\n            if (best == -1 || d < bestD - 1e-12 ||\n                (fabs(d - bestD) <= 1e-12 && cmpMortonCity(v, best))) {\n                best = v;\n                bestD = d;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return ord;\n}\n\ndouble estimate_group_cost(const vector<int>& group) {\n    vector<int> ord = sort_morton(group);\n    return optimize_chain_cost_only(ord);\n}\n\nvector<pair<int,int>> ask(const vector<int>& sub) {\n    cout << \"? \" << sub.size();\n    for (int v : sub) cout << ' ' << v;\n    cout << '\\n';\n    cout.flush();\n\n    vector<pair<int,int>> ret;\n    ret.reserve((int)sub.size() - 1);\n    for (int i = 0; i < (int)sub.size() - 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.push_back({a, b});\n    }\n    return ret;\n}\n\nvoid append_chain_edges(const vector<int>& sub, vector<pair<int,int>>& edges) {\n    for (int i = 1; i < (int)sub.size(); i++) {\n        int a = sub[i - 1], b = sub[i];\n        if (a > b) swap(a, b);\n        edges.push_back({a, b});\n    }\n}\n\nvector<vector<int>> makeContiguous(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n    vector<vector<int>> groups(M);\n    int pos = 0;\n    for (int gid : groupOrder) {\n        groups[gid] = vector<int>(cityOrder.begin() + pos, cityOrder.begin() + pos + G[gid]);\n        pos += G[gid];\n    }\n    return groups;\n}\n\ndouble span_cost(int dx, int dy, int cnt, int mode) {\n    double base = (mode == 0) ? (double)(dx + dy) : sqrt((double)dx * dx + (double)dy * dy);\n    return base * sqrt((double)cnt);\n}\n\nvoid kd_rec(const vector<int>& pts, const vector<GroupItem>& items,\n            vector<vector<int>>& ans, int mode) {\n    if ((int)items.size() == 1) {\n        ans[items[0].id] = pts;\n        return;\n    }\n\n    int n = (int)pts.size();\n    int m = (int)items.size();\n\n    vector<vector<char>> poss(m + 1, vector<char>(n + 1, 0));\n    poss[0][0] = 1;\n    for (int i = 0; i < m; i++) {\n        int sz = items[i].size;\n        for (int s = 0; s <= n; s++) {\n            if (!poss[i][s]) continue;\n            poss[i + 1][s] = 1;\n            if (s + sz <= n) poss[i + 1][s + sz] = 1;\n        }\n    }\n\n    vector<int> ordx = pts, ordy = pts;\n    sort(ordx.begin(), ordx.end(), cmpXCity);\n    sort(ordy.begin(), ordy.end(), cmpYCity);\n\n    vector<int> pxMinY(n), pxMaxY(n), sxMinY(n), sxMaxY(n);\n    vector<int> pyMinX(n), pyMaxX(n), syMinX(n), syMaxX(n);\n\n    for (int i = 0; i < n; i++) {\n        int v = ordx[i];\n        if (i == 0) pxMinY[i] = pxMaxY[i] = SY[v];\n        else {\n            pxMinY[i] = min(pxMinY[i - 1], SY[v]);\n            pxMaxY[i] = max(pxMaxY[i - 1], SY[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordx[i];\n        if (i == n - 1) sxMinY[i] = sxMaxY[i] = SY[v];\n        else {\n            sxMinY[i] = min(sxMinY[i + 1], SY[v]);\n            sxMaxY[i] = max(sxMaxY[i + 1], SY[v]);\n        }\n    }\n\n    for (int i = 0; i < n; i++) {\n        int v = ordy[i];\n        if (i == 0) pyMinX[i] = pyMaxX[i] = SX[v];\n        else {\n            pyMinX[i] = min(pyMinX[i - 1], SX[v]);\n            pyMaxX[i] = max(pyMaxX[i - 1], SX[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordy[i];\n        if (i == n - 1) syMinX[i] = syMaxX[i] = SX[v];\n        else {\n            syMinX[i] = min(syMinX[i + 1], SX[v]);\n            syMaxX[i] = max(syMaxX[i + 1], SX[v]);\n        }\n    }\n\n    double bestScore = INF;\n    int bestS = -1;\n    int bestAxis = 0; // 0:x, 1:y\n\n    for (int s = 1; s < n; s++) {\n        if (!poss[m][s]) continue;\n\n        {\n            int ldx = SX[ordx[s - 1]] - SX[ordx[0]];\n            int ldy = pxMaxY[s - 1] - pxMinY[s - 1];\n            int rdx = SX[ordx[n - 1]] - SX[ordx[s]];\n            int rdy = sxMaxY[s] - sxMinY[s];\n            double score = span_cost(ldx, ldy, s, mode) + span_cost(rdx, rdy, n - s, mode);\n            if (score < bestScore - 1e-9 ||\n                (fabs(score - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n                bestScore = score;\n                bestS = s;\n                bestAxis = 0;\n            }\n        }\n        {\n            int ldy = SY[ordy[s - 1]] - SY[ordy[0]];\n            int ldx = pyMaxX[s - 1] - pyMinX[s - 1];\n            int rdy = SY[ordy[n - 1]] - SY[ordy[s]];\n            int rdx = syMaxX[s] - syMinX[s];\n            double score = span_cost(ldx, ldy, s, mode) + span_cost(rdx, rdy, n - s, mode);\n            if (score < bestScore - 1e-9 ||\n                (fabs(score - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n                bestScore = score;\n                bestS = s;\n                bestAxis = 1;\n            }\n        }\n    }\n\n    if (bestS == -1) {\n        bestS = items[0].size;\n        if (bestS <= 0 || bestS >= n) bestS = n / 2;\n        bestAxis = 0;\n    }\n\n    vector<GroupItem> leftItems, rightItems;\n    int sum = bestS;\n    for (int i = m - 1; i >= 0; i--) {\n        int sz = items[i].size;\n        if (sum >= sz && poss[i][sum - sz]) {\n            leftItems.push_back(items[i]);\n            sum -= sz;\n        } else {\n            rightItems.push_back(items[i]);\n        }\n    }\n    reverse(leftItems.begin(), leftItems.end());\n    reverse(rightItems.begin(), rightItems.end());\n\n    const vector<int>& ord = (bestAxis == 0 ? ordx : ordy);\n    vector<int> leftPts(ord.begin(), ord.begin() + bestS);\n    vector<int> rightPts(ord.begin() + bestS, ord.end());\n\n    kd_rec(leftPts, leftItems, ans, mode);\n    kd_rec(rightPts, rightItems, ans, mode);\n}\n\nvector<vector<int>> makeKD(int mode) {\n    vector<vector<int>> ans(M);\n    vector<int> pts(N);\n    iota(pts.begin(), pts.end(), 0);\n    vector<GroupItem> items(M);\n    for (int i = 0; i < M; i++) items[i] = {G[i], i};\n    kd_rec(pts, items, ans, mode);\n    return ans;\n}\n\nPlan choose_plan(const vector<int>& group) {\n    Plan plan;\n    int g = (int)group.size();\n    if (g == 0) return plan;\n\n    auto ordMort = sort_morton(group);\n    plan.order = ordMort;\n    plan.estCost = optimize_chain_cost_only(ordMort);\n    if (g <= L) return plan;\n\n    auto base = optimize_chain_reconstruct(ordMort);\n    plan.estCost = base.first;\n    plan.adds = base.second;\n\n    auto try_order = [&](const vector<int>& ord) {\n        auto res = optimize_chain_reconstruct(ord);\n        if (res.first < plan.estCost - 1e-9) {\n            plan.estCost = res.first;\n            plan.order = ord;\n            plan.adds = res.second;\n        }\n    };\n\n    {\n        auto v = ordMort;\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n    {\n        auto v = sort_x(group);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n    {\n        auto v = sort_y(group);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n\n    int leftmost = *min_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n    int rightmost = *max_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n\n    {\n        auto v = nn_order(group, leftmost);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n    if (rightmost != leftmost) {\n        auto v = nn_order(group, rightmost);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n\n    return plan;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> Q >> L >> Wv;\n    G.resize(M);\n    for (int i = 0; i < M; i++) cin >> G[i];\n\n    vector<int> lx(N), rx(N), ly(N), ry(N);\n    for (int i = 0; i < N; i++) {\n        cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n        SX[i] = lx[i] + rx[i];\n        SY[i] = ly[i] + ry[i];\n        KEY_[i] = mortonEncode((uint32_t)SX[i], (uint32_t)SY[i]);\n    }\n\n    for (int i = 0; i < N; i++) {\n        distMat[i][i] = 0.0;\n        for (int j = i + 1; j < N; j++) {\n            long long dx = (long long)SX[i] - SX[j];\n            long long dy = (long long)SY[i] - SY[j];\n            double d = sqrt((double)dx * dx + (double)dy * dy);\n            distMat[i][j] = distMat[j][i] = d;\n        }\n    }\n\n    vector<int> groupIdsAsc(M), groupIdsDesc(M);\n    iota(groupIdsAsc.begin(), groupIdsAsc.end(), 0);\n    sort(groupIdsAsc.begin(), groupIdsAsc.end(), [&](int a, int b) {\n        if (G[a] != G[b]) return G[a] < G[b];\n        return a < b;\n    });\n    groupIdsDesc = groupIdsAsc;\n    reverse(groupIdsDesc.begin(), groupIdsDesc.end());\n\n    vector<int> allCities(N);\n    iota(allCities.begin(), allCities.end(), 0);\n\n    vector<int> cityMort = allCities;\n    sort(cityMort.begin(), cityMort.end(), cmpMortonCity);\n\n    vector<int> cityX = allCities;\n    sort(cityX.begin(), cityX.end(), cmpXCity);\n\n    vector<int> cityY = allCities;\n    sort(cityY.begin(), cityY.end(), cmpYCity);\n\n    vector<int> revMort = cityMort;\n    reverse(revMort.begin(), revMort.end());\n\n    double bestScore = INF;\n    vector<vector<int>> bestGroups;\n\n    auto try_candidate = [&](vector<vector<int>> cand) {\n        double sc = 0.0;\n        for (int gid = 0; gid < M; gid++) {\n            sc += estimate_group_cost(cand[gid]);\n            if (sc >= bestScore) break;\n        }\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestGroups = std::move(cand);\n        }\n    };\n\n    try_candidate(makeKD(0));\n    try_candidate(makeKD(1));\n    try_candidate(makeContiguous(cityMort, groupIdsAsc));\n    try_candidate(makeContiguous(cityMort, groupIdsDesc));\n    try_candidate(makeContiguous(revMort, groupIdsAsc));\n    try_candidate(makeContiguous(revMort, groupIdsDesc));\n    try_candidate(makeContiguous(cityX, groupIdsAsc));\n    try_candidate(makeContiguous(cityY, groupIdsAsc));\n\n    vector<Plan> plans(M);\n    for (int gid = 0; gid < M; gid++) {\n        plans[gid] = choose_plan(bestGroups[gid]);\n        if (plans[gid].order.empty()) plans[gid].order = bestGroups[gid];\n    }\n\n    vector<vector<pair<int,int>>> answerEdges(M);\n    int queriesUsed = 0;\n\n    for (int gid = 0; gid < M; gid++) {\n        const auto& ord = plans[gid].order;\n        int g = (int)ord.size();\n        answerEdges[gid].reserve(max(0, g - 1));\n\n        if (g <= 1) continue;\n        if (g == 2) {\n            int a = ord[0], b = ord[1];\n            if (a > b) swap(a, b);\n            answerEdges[gid].push_back({a, b});\n            continue;\n        }\n\n        if (g <= L) {\n            if (queriesUsed < Q) {\n                auto ret = ask(ord);\n                answerEdges[gid].insert(answerEdges[gid].end(), ret.begin(), ret.end());\n                queriesUsed++;\n            } else {\n                append_chain_edges(ord, answerEdges[gid]);\n            }\n        } else {\n            int pos = 0;\n            for (int t : plans[gid].adds) {\n                int msz = t + 1;\n                vector<int> sub(ord.begin() + pos, ord.begin() + pos + msz);\n                if (msz >= 3 && queriesUsed < Q) {\n                    auto ret = ask(sub);\n                    answerEdges[gid].insert(answerEdges[gid].end(), ret.begin(), ret.end());\n                    queriesUsed++;\n                } else {\n                    append_chain_edges(sub, answerEdges[gid]);\n                }\n                pos += t;\n            }\n        }\n\n        for (auto& e : answerEdges[gid]) {\n            if (e.first > e.second) swap(e.first, e.second);\n        }\n        sort(answerEdges[gid].begin(), answerEdges[gid].end());\n    }\n\n    cout << \"!\" << '\\n';\n    for (int gid = 0; gid < M; gid++) {\n        const auto& ord = plans[gid].order;\n        for (int i = 0; i < (int)ord.size(); i++) {\n            if (i) cout << ' ';\n            cout << ord[i];\n        }\n        cout << '\\n';\n        for (auto [a, b] : answerEdges[gid]) {\n            cout << a << ' ' << b << '\\n';\n        }\n    }\n    cout.flush();\n\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int r, c;\n};\n\nstruct Cmd {\n    char a, d;\n};\n\nstruct Edges {\n    uint16_t to[8];\n    uint8_t cnt = 0;\n};\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXV = 400;\nstatic constexpr int INF = 1e9;\n\nstruct Solver {\n    int N, M, V;\n    vector<Point> pts;\n    vector<int> cells;\n    array<char, MAXV> special{};\n    vector<vector<int>> cand; // candidate block cells per target, includes -1 (NONE)\n    mt19937 rng;\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n    const char dirC[4] = {'U', 'D', 'L', 'R'};\n\n    Solver(int N_, int M_, vector<Point> pts_)\n        : N(N_), M(M_), V(N_ * N_), pts(std::move(pts_)),\n          cells(M_), cand(M_), rng(712367821) {\n        special.fill(0);\n        for (int i = 0; i < M; i++) {\n            cells[i] = id(pts[i].r, pts[i].c);\n            special[cells[i]] = 1; // never place blocks on start/targets\n        }\n        build_candidates();\n    }\n\n    int id(int r, int c) const { return r * N + c; }\n    int row(int x) const { return x / N; }\n    int col(int x) const { return x % N; }\n    bool inside(int r, int c) const { return 0 <= r && r < N && 0 <= c && c < N; }\n\n    int manhattan_cell(int a, int b) const {\n        return abs(row(a) - row(b)) + abs(col(a) - col(b));\n    }\n\n    // Direction from 'from' to adjacent 'to': 0..3 = UDLR, else -1\n    int adj_dir(int from, int to) const {\n        int fr = row(from), fc = col(from);\n        int tr = row(to), tc = col(to);\n        for (int d = 0; d < 4; d++) {\n            if (fr + dr[d] == tr && fc + dc[d] == tc) return d;\n        }\n        return -1;\n    }\n\n    void build_candidates() {\n        for (int k = 1; k < M; k++) {\n            cand[k].push_back(-1); // NONE\n            int r = pts[k].r, c = pts[k].c;\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                int v = id(nr, nc);\n                if (!special[v]) cand[k].push_back(v);\n            }\n            sort(cand[k].begin(), cand[k].end());\n            cand[k].erase(unique(cand[k].begin(), cand[k].end()), cand[k].end());\n        }\n    }\n\n    vector<int> initial_assignment() const {\n        vector<int> asg(M, -1);\n        for (int k = 1; k < M; k++) {\n            int cur = cells[k], prv = cells[k - 1];\n            int r = row(cur), c = col(cur);\n            int pr = row(prv), pc = col(prv);\n\n            vector<int> pref_dirs;\n            // If column difference is smaller, vertical stopper is often good.\n            if (abs(pc - c) <= abs(pr - r)) {\n                if (pr <= r) pref_dirs = {1, 0, 3, 2}; // prefer block below, then above\n                else         pref_dirs = {0, 1, 2, 3}; // prefer block above, then below\n            } else {\n                if (pc <= c) pref_dirs = {3, 2, 1, 0}; // prefer block right, then left\n                else         pref_dirs = {2, 3, 0, 1}; // prefer block left, then right\n            }\n\n            int chosen = -1;\n            for (int pd : pref_dirs) {\n                for (int x : cand[k]) {\n                    if (x == -1) continue;\n                    if (adj_dir(cur, x) == pd) {\n                        chosen = x;\n                        break;\n                    }\n                }\n                if (chosen != -1) break;\n            }\n            if (chosen == -1) {\n                for (int x : cand[k]) {\n                    if (x != -1) { chosen = x; break; }\n                }\n            }\n            asg[k] = chosen;\n        }\n        return asg;\n    }\n\n    void build_transitions(const array<char, MAXV>& blocked, array<Edges, MAXV>& trans) const {\n        for (int p = 0; p < V; p++) {\n            trans[p].cnt = 0;\n            if (blocked[p]) continue;\n            int r = row(p), c = col(p);\n            int tmp[8], cnt = 0;\n            auto add = [&](int v) {\n                for (int i = 0; i < cnt; i++) if (tmp[i] == v) return;\n                tmp[cnt++] = v;\n            };\n\n            // Slides first\n            for (int d = 0; d < 4; d++) {\n                int rr = r, cc = c;\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int nv = id(nr, nc);\n                    if (blocked[nv]) break;\n                    rr = nr; cc = nc;\n                }\n                int v = id(rr, cc);\n                if (v != p) add(v);\n            }\n            // Moves\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                int v = id(nr, nc);\n                if (!blocked[v]) add(v);\n            }\n\n            trans[p].cnt = (uint8_t)cnt;\n            for (int i = 0; i < cnt; i++) trans[p].to[i] = (uint16_t)tmp[i];\n        }\n    }\n\n    int bfs_dist_trans(const array<Edges, MAXV>& trans, int src, int dst) const {\n        if (src == dst) return 0;\n        array<int, MAXV> dist;\n        dist.fill(-1);\n        int q[MAXV], qh = 0, qt = 0;\n        dist[src] = 0;\n        q[qt++] = src;\n        while (qh < qt) {\n            int u = q[qh++];\n            int nd = dist[u] + 1;\n            const auto& e = trans[u];\n            for (int i = 0; i < e.cnt; i++) {\n                int v = e.to[i];\n                if (dist[v] != -1) continue;\n                if (v == dst) return nd;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n        return -1;\n    }\n\n    int bfs_dist_board(const array<char, MAXV>& blocked, int src, int dst, int forbid = -1) const {\n        if (src == dst) return 0;\n        if (src == forbid || dst == forbid) return -1;\n        array<int, MAXV> dist;\n        dist.fill(-1);\n        int q[MAXV], qh = 0, qt = 0;\n        dist[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            int ur = row(u), uc = col(u);\n            int nd = dist[u] + 1;\n\n            // Slides first\n            for (int d = 0; d < 4; d++) {\n                int rr = ur, cc = uc;\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int nv = id(nr, nc);\n                    if (blocked[nv]) break;\n                    rr = nr; cc = nc;\n                }\n                int v = id(rr, cc);\n                if (v == u || v == forbid || dist[v] != -1) continue;\n                if (v == dst) return nd;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n            // Moves\n            for (int d = 0; d < 4; d++) {\n                int nr = ur + dr[d], nc = uc + dc[d];\n                if (!inside(nr, nc)) continue;\n                int v = id(nr, nc);\n                if (blocked[v] || v == forbid || dist[v] != -1) continue;\n                if (v == dst) return nd;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n        return -1;\n    }\n\n    void bfs_all_board(const array<char, MAXV>& blocked, int src, int forbid,\n                       array<int, MAXV>& dist,\n                       array<int, MAXV>& prev_pos,\n                       array<int, MAXV>& prev_act) const {\n        dist.fill(-1);\n        prev_pos.fill(-1);\n        prev_act.fill(-1);\n        if (src == forbid) return;\n\n        int q[MAXV], qh = 0, qt = 0;\n        dist[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            int ur = row(u), uc = col(u);\n            int nd = dist[u] + 1;\n\n            // Slides first: acts 4..7\n            for (int d = 0; d < 4; d++) {\n                int rr = ur, cc = uc;\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int nv = id(nr, nc);\n                    if (blocked[nv]) break;\n                    rr = nr; cc = nc;\n                }\n                int v = id(rr, cc);\n                if (v == u || v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                prev_pos[v] = u;\n                prev_act[v] = 4 + d;\n                q[qt++] = v;\n            }\n            // Moves: acts 0..3\n            for (int d = 0; d < 4; d++) {\n                int nr = ur + dr[d], nc = uc + dc[d];\n                if (!inside(nr, nc)) continue;\n                int v = id(nr, nc);\n                if (blocked[v] || v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                prev_pos[v] = u;\n                prev_act[v] = d;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    bool reconstruct_path(int src, int dst,\n                          const array<int, MAXV>& prev_pos,\n                          const array<int, MAXV>& prev_act,\n                          vector<int>& acts) const {\n        acts.clear();\n        if (src == dst) return true;\n        if (prev_pos[dst] == -1) return false;\n        int cur = dst;\n        while (cur != src) {\n            if (cur < 0 || prev_pos[cur] < 0) return false;\n            acts.push_back(prev_act[cur]);\n            cur = prev_pos[cur];\n        }\n        reverse(acts.begin(), acts.end());\n        return true;\n    }\n\n    bool bfs_path_board(const array<char, MAXV>& blocked, int src, int dst, int forbid,\n                        vector<int>& acts) const {\n        if (src == dst) {\n            acts.clear();\n            return true;\n        }\n        array<int, MAXV> dist, prev_pos, prev_act;\n        bfs_all_board(blocked, src, forbid, dist, prev_pos, prev_act);\n        if (dist[dst] == -1) return false;\n        return reconstruct_path(src, dst, prev_pos, prev_act, acts);\n    }\n\n    void append_acts(vector<Cmd>& ans, const vector<int>& acts) const {\n        for (int a : acts) {\n            if (a < 4) ans.push_back({'M', dirC[a]});\n            else       ans.push_back({'S', dirC[a - 4]});\n        }\n    }\n\n    Cmd alter_cmd(int from, int block_cell) const {\n        int d = adj_dir(from, block_cell);\n        return {'A', dirC[d]};\n    }\n\n    int eval_assignment(const vector<int>& asg, int lambda, int cutoff = INF) const {\n        array<char, MAXV> blocked{};\n        blocked.fill(0);\n        int uniq = 0;\n        for (int k = 1; k < M; k++) {\n            int x = asg[k];\n            if (x == -1) continue;\n            if (!blocked[x]) {\n                blocked[x] = 1;\n                uniq++;\n            }\n        }\n\n        int total = lambda * uniq;\n        if (total >= cutoff) return total;\n\n        array<Edges, MAXV> trans;\n        build_transitions(blocked, trans);\n\n        for (int i = 0; i + 1 < M; i++) {\n            int d = bfs_dist_trans(trans, cells[i], cells[i + 1]);\n            if (d == -1) return INF;\n            total += d;\n            if (total >= cutoff) return total;\n        }\n        return total;\n    }\n\n    vector<int> local_search_assignment(int lambda) const {\n        vector<int> asg = initial_assignment();\n        int cur_obj = eval_assignment(asg, lambda);\n\n        for (int round = 0; round < 3; round++) {\n            bool changed = false;\n            for (int k = 1; k < M; k++) {\n                int old = asg[k];\n                int best_c = old;\n                int best_obj = cur_obj;\n\n                for (int x : cand[k]) {\n                    if (x == old) continue;\n                    asg[k] = x;\n                    int obj = eval_assignment(asg, lambda, best_obj);\n                    if (obj < best_obj) {\n                        best_obj = obj;\n                        best_c = x;\n                    }\n                }\n                asg[k] = best_c;\n                if (best_c != old) {\n                    cur_obj = best_obj;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n        return asg;\n    }\n\n    vector<Cmd> build_solution(const vector<int>& asg) const {\n        vector<Cmd> ans;\n        if (M <= 1) return ans;\n\n        // Planned unique blocks\n        array<char, MAXV> planned{};\n        planned.fill(0);\n        vector<int> uniq_blocks;\n        for (int k = 1; k < M; k++) {\n            int x = asg[k];\n            if (x == -1) continue;\n            if (!planned[x]) {\n                planned[x] = 1;\n                uniq_blocks.push_back(x);\n            }\n        }\n\n        int target1 = cells[1];\n        int start = cells[0];\n\n        // Reserve one \"terminal\" block to be placed last, preferably target1's stopper\n        int terminal = -1;\n        if (asg[1] != -1 && planned[asg[1]]) terminal = asg[1];\n        else if (!uniq_blocks.empty()) {\n            int best_md = INF;\n            for (int b : uniq_blocks) {\n                int md = manhattan_cell(b, target1);\n                if (md < best_md) {\n                    best_md = md;\n                    terminal = b;\n                }\n            }\n        }\n\n        array<char, MAXV> blocked{};\n        blocked.fill(0);\n        int cur = start;\n\n        vector<int> rem;\n        rem.reserve(uniq_blocks.size());\n        for (int b : uniq_blocks) if (b != terminal) rem.push_back(b);\n\n        // Greedy construction of non-terminal blocks\n        while (!rem.empty()) {\n            array<int, MAXV> dist, prev_pos, prev_act;\n            bfs_all_board(blocked, cur, target1, dist, prev_pos, prev_act);\n\n            int best_i = -1, best_v = -1, best_d = INF;\n            for (int i = 0; i < (int)rem.size(); i++) {\n                int b = rem[i];\n                int br = row(b), bc = col(b);\n                for (int d = 0; d < 4; d++) {\n                    int vr = br + dr[d], vc = bc + dc[d];\n                    if (!inside(vr, vc)) continue;\n                    int v = id(vr, vc);\n                    if (v == target1 || blocked[v]) continue;\n                    if (dist[v] == -1) continue;\n                    if (dist[v] < best_d) {\n                        best_d = dist[v];\n                        best_i = i;\n                        best_v = v;\n                    }\n                }\n            }\n\n            if (best_i == -1) break; // remaining blocks unreachable before target1\n\n            vector<int> acts;\n            if (!reconstruct_path(cur, best_v, prev_pos, prev_act, acts)) break;\n            append_acts(ans, acts);\n            cur = best_v;\n\n            int b = rem[best_i];\n            ans.push_back(alter_cmd(cur, b));\n            blocked[b] = 1;\n\n            rem[best_i] = rem.back();\n            rem.pop_back();\n        }\n\n        // Place terminal last, choose vantage that is also good for reaching target1 afterwards\n        if (terminal != -1 && !blocked[terminal]) {\n            array<int, MAXV> dist, prev_pos, prev_act;\n            bfs_all_board(blocked, cur, target1, dist, prev_pos, prev_act);\n\n            int best_v = -1;\n            int best_score = INF;\n            int best_dist_only = INF;\n            int fallback_v = -1;\n\n            blocked[terminal] = 1;\n            for (int d = 0; d < 4; d++) {\n                int vr = row(terminal) + dr[d], vc = col(terminal) + dc[d];\n                if (!inside(vr, vc)) continue;\n                int v = id(vr, vc);\n                if (v == target1 || blocked[v]) continue; // blocked[terminal] only; v can't equal terminal\n                if (dist[v] == -1) continue;\n\n                if (dist[v] < best_dist_only) {\n                    best_dist_only = dist[v];\n                    fallback_v = v;\n                }\n\n                int d2 = bfs_dist_board(blocked, v, target1, -1);\n                if (d2 == -1) continue;\n                int score = dist[v] + d2;\n                if (score < best_score) {\n                    best_score = score;\n                    best_v = v;\n                }\n            }\n            blocked[terminal] = 0;\n\n            if (best_v == -1) best_v = fallback_v;\n\n            if (best_v != -1) {\n                vector<int> acts;\n                if (bfs_path_board(blocked, cur, best_v, target1, acts)) {\n                    append_acts(ans, acts);\n                    cur = best_v;\n                    ans.push_back(alter_cmd(cur, terminal));\n                    blocked[terminal] = 1;\n                }\n            }\n        }\n\n        // Final board is now 'blocked'\n        array<Edges, MAXV> trans;\n        build_transitions(blocked, trans);\n\n        vector<int> pairDist(max(0, M - 1), -1);\n        long long sumAll = 0, sumAfter1 = 0;\n        for (int i = 0; i + 1 < M; i++) {\n            pairDist[i] = bfs_dist_trans(trans, cells[i], cells[i + 1]);\n            if (pairDist[i] == -1) return {};\n            sumAll += pairDist[i];\n            if (i >= 1) sumAfter1 += pairDist[i];\n        }\n\n        long long costA = INF, costB = INF;\n        int dCurT1 = bfs_dist_trans(trans, cur, target1);\n        if (dCurT1 != -1) costA = (long long)dCurT1 + sumAfter1;\n\n        int dCurStartAvoidT1 = bfs_dist_board(blocked, cur, start, target1);\n        if (dCurStartAvoidT1 != -1) costB = (long long)dCurStartAvoidT1 + sumAll;\n\n        bool goStart = (costB < costA);\n\n        if (goStart) {\n            vector<int> acts;\n            if (!bfs_path_board(blocked, cur, start, target1, acts)) return {};\n            append_acts(ans, acts);\n            cur = start;\n            for (int i = 1; i < M; i++) {\n                acts.clear();\n                if (!bfs_path_board(blocked, cur, cells[i], -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = cells[i];\n            }\n        } else {\n            vector<int> acts;\n            if (!bfs_path_board(blocked, cur, target1, -1, acts)) return {};\n            append_acts(ans, acts);\n            cur = target1;\n            for (int i = 2; i < M; i++) {\n                acts.clear();\n                if (!bfs_path_board(blocked, cur, cells[i], -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = cells[i];\n            }\n        }\n\n        return ans;\n    }\n\n    pair<bool, int> simulate(const vector<Cmd>& ans) const {\n        array<char, MAXV> blocked{};\n        blocked.fill(0);\n        int cur = cells[0];\n        int t = 1;\n\n        auto dir_idx = [&](char d) -> int {\n            if (d == 'U') return 0;\n            if (d == 'D') return 1;\n            if (d == 'L') return 2;\n            return 3;\n        };\n\n        for (const auto& cmd : ans) {\n            int d = dir_idx(cmd.d);\n            if (cmd.a == 'M') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                if (blocked[v]) return {false, (int)ans.size()};\n                cur = v;\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'S') {\n                int rr = row(cur), cc = col(cur);\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int v = id(nr, nc);\n                    if (blocked[v]) break;\n                    rr = nr; cc = nc;\n                }\n                cur = id(rr, cc);\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'A') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                blocked[v] ^= 1;\n            } else {\n                return {false, (int)ans.size()};\n            }\n        }\n\n        bool ok = (t == M && (int)ans.size() <= 2 * N * M);\n        return {ok, (int)ans.size()};\n    }\n\n    vector<Cmd> solve() const {\n        // Safe fallback: no blocks\n        vector<int> none(M, -1);\n        vector<Cmd> best = build_solution(none);\n        auto [ok_best, len_best] = simulate(best);\n        if (!ok_best) {\n            // Extremely unlikely, but ensure some output\n            best.clear();\n            int cur = cells[0];\n            for (int i = 1; i < M; i++) {\n                int tr = row(cells[i]), tc = col(cells[i]);\n                int cr = row(cur), cc = col(cur);\n                while (cr < tr) best.push_back({'M', 'D'}), cr++;\n                while (cr > tr) best.push_back({'M', 'U'}), cr--;\n                while (cc < tc) best.push_back({'M', 'R'}), cc++;\n                while (cc > tc) best.push_back({'M', 'L'}), cc--;\n                cur = cells[i];\n            }\n            tie(ok_best, len_best) = simulate(best);\n        }\n\n        // Try a couple of block penalties\n        for (int lambda : {0, 2}) {\n            vector<int> asg = local_search_assignment(lambda);\n            vector<Cmd> cand_ans = build_solution(asg);\n            auto [ok, len] = simulate(cand_ans);\n            if (ok && len < len_best) {\n                best = std::move(cand_ans);\n                len_best = len;\n            }\n        }\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<Point> pts(M);\n    for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n    if (M <= 1) return 0;\n\n    Solver solver(N, M, pts);\n    vector<Cmd> ans = solver.solve();\n\n    for (auto &c : ans) {\n        cout << c.a << ' ' << c.d << '\\n';\n    }\n    return 0;\n}"},"2":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ld = long double;\nstatic constexpr int BOARD = 10000;\nstatic constexpr ld INF_CAP = 1e30L;\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n    int area() const { return (r - l) * (t - b); }\n};\n\nenum Action {\n    EXP_L = 0,\n    EXP_R = 1,\n    EXP_B = 2,\n    EXP_T = 3,\n    SHR_L = 4,\n    SHR_R = 5,\n    SHR_B = 6,\n    SHR_T = 7\n};\n\nstatic constexpr int MASK_EXP =\n    (1 << EXP_L) | (1 << EXP_R) | (1 << EXP_B) | (1 << EXP_T);\nstatic constexpr int MASK_SHR =\n    (1 << SHR_L) | (1 << SHR_R) | (1 << SHR_B) | (1 << SHR_T);\nstatic constexpr int MASK_ALL = MASK_EXP | MASK_SHR;\n\nstruct Move {\n    bool valid = false;\n    int action = 0;\n    int delta = 0;\n    int freecap = 0;\n    int prio = 0;\n    ld gain = 0;\n    ld sec = 0;\n};\n\nstruct Params {\n    vector<ld> caps;\n    int order_mode = 0;\n    bool reverse_axis = false;\n    array<int, 8> action_prio{};\n};\n\nstruct BSPParams {\n    ld err_w = 0.5L;\n    ld aspect_w = 0.02L;\n    ld step_w = 0.01L;\n    int orient_bias = 0; // -1: horizontal, +1: vertical\n    int top_try = 8;\n    bool smart_bias = true;\n};\n\nstruct SplitCand {\n    bool vertical = true;\n    int cut = 0;\n    vector<int> left, right;\n    ld score = 0;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int mod) {\n        return (int)(next_u64() % (uint64_t)mod);\n    }\n    ld uniform() {\n        return (next_u64() >> 11) * (1.0L / (1ULL << 53));\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n};\n\nstruct Solver {\n    int n;\n    vector<int> xs, ys, rs;\n    vector<ld> sqrs;\n    vector<int> nearest_idx;\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    static bool overlap1d(int l1, int r1, int l2, int r2) {\n        return max(l1, l2) < min(r1, r2);\n    }\n\n    static int ceil_div_int(int a, int b) {\n        return (a + b - 1) / b;\n    }\n\n    ld satisfaction(ld need, ld area) const {\n        if (need <= 0 || area <= 0) return 0;\n        ld t = min(need, area) / max(need, area);\n        ld u = 1.0L - t;\n        return 1.0L - u * u;\n    }\n\n    ld total_score(const vector<Rect>& rects) const {\n        ld res = 0;\n        for (int i = 0; i < n; ++i) res += satisfaction((ld)rs[i], (ld)rects[i].area());\n        return res;\n    }\n\n    long long occupied_area(const vector<Rect>& rects) const {\n        long long s = 0;\n        for (auto &r : rects) s += r.area();\n        return s;\n    }\n\n    vector<Rect> initial_rects() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; ++i) rects[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n        return rects;\n    }\n\n    void apply_move(Rect& rc, int action, int delta) const {\n        switch (action) {\n            case EXP_L: rc.l -= delta; break;\n            case EXP_R: rc.r += delta; break;\n            case EXP_B: rc.b -= delta; break;\n            case EXP_T: rc.t += delta; break;\n            case SHR_L: rc.l += delta; break;\n            case SHR_R: rc.r -= delta; break;\n            case SHR_B: rc.b += delta; break;\n            case SHR_T: rc.t -= delta; break;\n        }\n    }\n\n    bool better_move(const Move& a, const Move& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const ld EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        if (a.delta < b.delta) return true;\n        if (a.delta > b.delta) return false;\n        if (a.freecap > b.freecap) return true;\n        if (a.freecap < b.freecap) return false;\n        return a.prio < b.prio;\n    }\n\n    void compute_expand_limits(int i, const vector<Rect>& rects,\n                               int& maxL, int& maxR, int& maxB, int& maxT) const {\n        const Rect& a = rects[i];\n        int limL = 0, limR = BOARD, limB = 0, limT = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& o = rects[j];\n            if (overlap1d(a.b, a.t, o.b, o.t)) {\n                if (o.r <= a.l) limL = max(limL, o.r);\n                if (o.l >= a.r) limR = min(limR, o.l);\n            }\n            if (overlap1d(a.l, a.r, o.l, o.r)) {\n                if (o.t <= a.b) limB = max(limB, o.t);\n                if (o.b >= a.t) limT = min(limT, o.b);\n            }\n        }\n        maxL = a.l - limL;\n        maxR = limR - a.r;\n        maxB = a.b - limB;\n        maxT = limT - a.t;\n    }\n\n    static void add_target_lengths(vector<int>& v, ld target, int cur, bool expand_mode) {\n        const ld eps = 1e-12L;\n        int f = (int)floor(target + eps);\n        int c = (int)ceil(target - eps);\n        if (expand_mode) {\n            if (f > cur) v.push_back(f);\n            if (c > cur) v.push_back(c);\n        } else {\n            if (f >= 1 && f < cur) v.push_back(f);\n            if (c >= 1 && c < cur) v.push_back(c);\n        }\n    }\n\n    Move best_move_for_rect(int i, const vector<Rect>& rects,\n                            ld shape_cap, bool aggressive,\n                            const array<int, 8>& prio_map,\n                            int allowed_mask) const {\n        const Rect& cur = rects[i];\n        int w = cur.r - cur.l;\n        int h = cur.t - cur.b;\n        int area = w * h;\n        int need = rs[i];\n        ld cur_sat = satisfaction((ld)need, (ld)area);\n\n        int maxL, maxR, maxB, maxT;\n        compute_expand_limits(i, rects, maxL, maxR, maxB, maxT);\n\n        int marginL = xs[i] - cur.l;\n        int marginR = cur.r - (xs[i] + 1);\n        int marginB = ys[i] - cur.b;\n        int marginT = cur.t - (ys[i] + 1);\n\n        vector<Move> cands;\n\n        auto push_candidate = [&](int action, int delta, int freecap) {\n            if (!(allowed_mask & (1 << action))) return;\n            if (delta <= 0) return;\n            for (const auto& mv : cands) {\n                if (mv.action == action && mv.delta == delta) return;\n            }\n            Rect nr = cur;\n            apply_move(nr, action, delta);\n            int nw = nr.r - nr.l;\n            int nh = nr.t - nr.b;\n            int ns = nw * nh;\n            ld g = satisfaction((ld)need, (ld)ns) - cur_sat;\n            if (g <= 1e-18L) return;\n\n            int nL = xs[i] - nr.l;\n            int nR = nr.r - (xs[i] + 1);\n            int nB = ys[i] - nr.b;\n            int nT = nr.t - (ys[i] + 1);\n\n            ld aspect = (ld)max(nw, nh) / (ld)min(nw, nh);\n            ld imbalance = (ld)(abs(nL - nR) + abs(nB - nT)) / (ld)(nw + nh);\n            ld err = fabsl((ld)ns - (ld)need) / (ld)need;\n            ld sec = err + 0.01L * aspect + 0.02L * imbalance;\n\n            Move mv;\n            mv.valid = true;\n            mv.action = action;\n            mv.delta = delta;\n            mv.freecap = freecap;\n            mv.prio = prio_map[action];\n            mv.gain = g;\n            mv.sec = sec;\n            cands.push_back(mv);\n        };\n\n        if (area < need) {\n            // Expand horizontally.\n            ld exactW = (ld)need / (ld)h;\n            ld limitedW = min(exactW, sqrs[i] * shape_cap);\n            vector<int> wtars;\n            add_target_lengths(wtars, limitedW, w, true);\n            add_target_lengths(wtars, exactW, w, true);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_expand_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = Wtar - w;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactW - 1e-12L) > w + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactW - (ld)w - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side(EXP_L, maxL);\n            gen_expand_side(EXP_R, maxR);\n\n            // Expand vertically.\n            ld exactH = (ld)need / (ld)w;\n            ld limitedH = min(exactH, sqrs[i] * shape_cap);\n            vector<int> htars;\n            add_target_lengths(htars, limitedH, h, true);\n            add_target_lengths(htars, exactH, h, true);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_expand_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = Htar - h;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactH - 1e-12L) > h + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactH - (ld)h - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side_v(EXP_B, maxB);\n            gen_expand_side_v(EXP_T, maxT);\n        } else if (area > need) {\n            // Shrink horizontally.\n            ld exactW = (ld)need / (ld)h;\n            vector<int> wtars;\n            add_target_lengths(wtars, exactW, w, false);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_shrink_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = w - Wtar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)w - exactW - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side(SHR_L, marginL);\n            gen_shrink_side(SHR_R, marginR);\n\n            // Shrink vertically.\n            ld exactH = (ld)need / (ld)w;\n            vector<int> htars;\n            add_target_lengths(htars, exactH, h, false);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_shrink_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = h - Htar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)h - exactH - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side_v(SHR_B, marginB);\n            gen_shrink_side_v(SHR_T, marginT);\n        }\n\n        Move best;\n        for (const auto& mv : cands) {\n            if (better_move(mv, best)) best = mv;\n        }\n        return best;\n    }\n\n    vector<int> build_order(const vector<Rect>& rects, int mode, bool reverse_axis) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n\n        if (mode == 0) return ord;\n\n        if (mode == 1) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return rs[a] > rs[b];\n            });\n        } else if (mode == 2) {\n            vector<ld> key(n);\n            for (int i = 0; i < n; ++i) key[i] = 1.0L - satisfaction((ld)rs[i], (ld)rects[i].area());\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        } else if (mode == 3) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] < xs[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] > xs[b];\n                });\n            }\n        } else if (mode == 4) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] < ys[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] > ys[b];\n                });\n            }\n        } else if (mode == 5) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rs[a] - rects[a].area()) > (rs[b] - rects[b].area());\n            });\n        } else if (mode == 6) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rects[a].area() - rs[a]) > (rects[b].area() - rs[b]);\n            });\n        }\n\n        return ord;\n    }\n\n    long long sum_requests(const vector<int>& ids) const {\n        long long s = 0;\n        for (int id : ids) s += rs[id];\n        return s;\n    }\n\n    static ld log_aspect(int w, int h) {\n        ld a = (ld)max(w, h) / (ld)min(w, h);\n        return log(a);\n    }\n\n    vector<SplitCand> generate_bsp_candidates(const vector<int>& ids,\n                                              int lx, int ly, int rx, int ry,\n                                              const BSPParams& par,\n                                              bool optimize_score) {\n        vector<SplitCand> res;\n        int m = (int)ids.size();\n        if (m <= 1) return res;\n\n        int W = rx - lx, H = ry - ly;\n        ld regionArea = (ld)W * (ld)H;\n\n        vector<int> xord = ids, yord = ids;\n        sort(xord.begin(), xord.end(), [&](int a, int b) {\n            if (xs[a] != xs[b]) return xs[a] < xs[b];\n            return ys[a] < ys[b];\n        });\n        sort(yord.begin(), yord.end(), [&](int a, int b) {\n            if (ys[a] != ys[b]) return ys[a] < ys[b];\n            return xs[a] < xs[b];\n        });\n\n        auto make_score = [&](bool vertical, int k, int cut,\n                              const vector<int>& left, const vector<int>& right,\n                              long long reqL) -> SplitCand {\n            SplitCand c;\n            c.vertical = vertical;\n            c.cut = cut;\n            c.left = left;\n            c.right = right;\n\n            long long reqTot = reqL + (sum_requests(right));\n            long long reqR = reqTot - reqL;\n\n            ld areaL, areaR;\n            int w1, h1, w2, h2, step;\n            if (vertical) {\n                w1 = cut - lx; h1 = H;\n                w2 = rx - cut; h2 = H;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = H;\n            } else {\n                w1 = W; h1 = cut - ly;\n                w2 = W; h2 = ry - cut;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = W;\n            }\n\n            ld proxy = (ld)left.size() * satisfaction((ld)reqL, areaL)\n                     + (ld)right.size() * satisfaction((ld)reqR, areaR);\n\n            ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n            ld err = fabsl(areaL - scaledL) / regionArea;\n            ld shape = log_aspect(w1, h1) + log_aspect(w2, h2);\n\n            ld score;\n            if (optimize_score) {\n                score = proxy\n                      - par.err_w * err\n                      - par.aspect_w * shape\n                      - par.step_w * ((ld)step / (ld)BOARD);\n\n                if (par.orient_bias == 1 && vertical) score += 1e-3L;\n                if (par.orient_bias == -1 && !vertical) score += 1e-3L;\n                if (par.smart_bias) {\n                    if (W > H && vertical) score += 5e-4L;\n                    if (H > W && !vertical) score += 5e-4L;\n                }\n                score += rng.uniform() * 1e-6L;\n            } else {\n                score = -(ld)abs(2 * k - m)\n                      - 0.05L * shape\n                      - 0.001L * ((ld)step / (ld)BOARD)\n                      + rng.uniform() * 1e-6L;\n            }\n            c.score = score;\n            return c;\n        };\n\n        // Vertical splits.\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[xord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int xL = xs[xord[k - 1]];\n                int xR = xs[xord[k]];\n                int lo = max(lx + 1, xL + 1);\n                int hi = min(rx - 1, xR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, lx + ceil_div_int(k, H));\n                int ahi = min(hi, rx - ceil_div_int(m - k, H));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)lx + scaledL / (ld)H;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    if (c < alo) c = alo;\n                    if (c > ahi) c = ahi;\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(xord.begin(), xord.begin() + k);\n                vector<int> right(xord.begin() + k, xord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(true, k, cut, left, right, reqL));\n                }\n            }\n        }\n\n        // Horizontal splits.\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[yord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int yL = ys[yord[k - 1]];\n                int yR = ys[yord[k]];\n                int lo = max(ly + 1, yL + 1);\n                int hi = min(ry - 1, yR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, ly + ceil_div_int(k, W));\n                int ahi = min(hi, ry - ceil_div_int(m - k, W));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)ly + scaledL / (ld)W;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    if (c < alo) c = alo;\n                    if (c > ahi) c = ahi;\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(yord.begin(), yord.begin() + k);\n                vector<int> right(yord.begin() + k, yord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(false, k, cut, left, right, reqL));\n                }\n            }\n        }\n\n        sort(res.begin(), res.end(), [&](const SplitCand& a, const SplitCand& b) {\n            return a.score > b.score;\n        });\n        return res;\n    }\n\n    bool partition_rec_simple(const vector<int>& ids,\n                              int lx, int ly, int rx, int ry,\n                              vector<Rect>& out) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        BSPParams dummy;\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, dummy, false);\n        if (cands.empty()) return false;\n\n        for (const auto& c : cands) {\n            if (c.vertical) {\n                if (partition_rec_simple(c.left, lx, ly, c.cut, ry, out) &&\n                    partition_rec_simple(c.right, c.cut, ly, rx, ry, out)) return true;\n            } else {\n                if (partition_rec_simple(c.left, lx, ly, rx, c.cut, out) &&\n                    partition_rec_simple(c.right, lx, c.cut, rx, ry, out)) return true;\n            }\n        }\n        return false;\n    }\n\n    bool partition_rec_opt(const vector<int>& ids,\n                           int lx, int ly, int rx, int ry,\n                           vector<Rect>& out,\n                           const BSPParams& par,\n                           int depth) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, par, true);\n        if (cands.empty()) {\n            return partition_rec_simple(ids, lx, ly, rx, ry, out);\n        }\n\n        int limit = min((int)cands.size(), par.top_try + (depth <= 2 ? 4 : 0));\n        for (int idx = 0; idx < limit; ++idx) {\n            const auto& c = cands[idx];\n            bool ok;\n            if (c.vertical) {\n                ok = partition_rec_opt(c.left, lx, ly, c.cut, ry, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, c.cut, ly, rx, ry, out, par, depth + 1);\n            } else {\n                ok = partition_rec_opt(c.left, lx, ly, rx, c.cut, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, lx, c.cut, rx, ry, out, par, depth + 1);\n            }\n            if (ok) return true;\n        }\n\n        return partition_rec_simple(ids, lx, ly, rx, ry, out);\n    }\n\n    vector<Rect> build_partition_solution(const BSPParams& par) {\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        vector<Rect> rects(n, {0, 0, 0, 0});\n        bool ok = partition_rec_opt(ids, 0, 0, BOARD, BOARD, rects, par, 0);\n        if (!ok) return initial_rects();\n        for (int i = 0; i < n; ++i) {\n            if (!(0 <= rects[i].l && rects[i].l < rects[i].r && rects[i].r <= BOARD &&\n                  0 <= rects[i].b && rects[i].b < rects[i].t && rects[i].t <= BOARD)) {\n                return initial_rects();\n            }\n            if (!(rects[i].l <= xs[i] && xs[i] < rects[i].r &&\n                  rects[i].b <= ys[i] && ys[i] < rects[i].t)) {\n                return initial_rects();\n            }\n        }\n        return rects;\n    }\n\n    ld optimize(vector<Rect>& rects, const Params& params) {\n        long long occ = occupied_area(rects);\n\n        // For near-full tilings, first release space from oversized rectangles.\n        if (occ > 95000000LL) {\n            for (int rep = 0; rep < 2; ++rep) {\n                bool any = false;\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n                if (!any) break;\n            }\n        }\n\n        // Main passes.\n        for (int pass = 0; pass < (int)params.caps.size(); ++pass) {\n            ld cap = params.caps[pass];\n            bool aggressive = (cap > 1e20L);\n            int mode = aggressive ? ((pass & 1) ? 5 : 2) : params.order_mode;\n            vector<int> ord = build_order(rects, mode, params.reverse_axis);\n\n            bool any = false;\n            for (int idx : ord) {\n                Move mv = best_move_for_rect(idx, rects, cap, aggressive,\n                                             params.action_prio, MASK_ALL);\n                if (mv.valid) {\n                    apply_move(rects[idx], mv.action, mv.delta);\n                    any = true;\n                }\n            }\n            if (!any && aggressive) break;\n        }\n\n        // Final polish: shrink -> expand -> mixed.\n        for (int rep = 0; rep < 2; ++rep) {\n            bool any = false;\n\n            {\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 5, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_EXP);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 2, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_ALL);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return total_score(rects);\n    }\n\n    array<int, 8> random_action_priority() {\n        vector<int> ord(8);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n        array<int, 8> pr{};\n        for (int i = 0; i < 8; ++i) pr[ord[i]] = i;\n        return pr;\n    }\n\n    Params random_constructive_params() {\n        Params p;\n        ld c0 = 0.85L + 0.40L * rng.uniform();\n        p.caps = {c0, c0 * 1.35L, c0 * 1.8L, c0 * 2.5L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.25L) p.order_mode = 0;\n        else if (u < 0.48L) p.order_mode = 1;\n        else if (u < 0.70L) p.order_mode = 2;\n        else if (u < 0.85L) p.order_mode = 5;\n        else if (u < 0.925L) p.order_mode = 3;\n        else p.order_mode = 4;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_perturb_params() {\n        Params p;\n        ld c0 = 0.95L + 0.55L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, c0 * 2.2L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 2;\n        else if (u < 0.70L) p.order_mode = 5;\n        else if (u < 0.90L) p.order_mode = 6;\n        else p.order_mode = 1;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_partition_params() {\n        Params p;\n        ld c0 = 1.00L + 0.35L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 6;\n        else if (u < 0.75L) p.order_mode = 2;\n        else if (u < 0.92L) p.order_mode = 5;\n        else p.order_mode = 1;\n\n        p.reverse_axis = false;\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    BSPParams random_bsp_params() {\n        BSPParams p;\n        p.err_w = 0.20L + 0.80L * rng.uniform();\n        p.aspect_w = 0.008L + 0.030L * rng.uniform();\n        p.step_w = 0.000L + 0.030L * rng.uniform();\n        p.orient_bias = rng.next_int(3) - 1;\n        p.top_try = 5 + rng.next_int(6);\n        p.smart_bias = true;\n        return p;\n    }\n\n    int weighted_pick(const vector<ld>& w, const vector<char>& banned) {\n        ld sum = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) sum += w[i];\n        if (sum <= 0) {\n            vector<int> cand;\n            for (int i = 0; i < n; ++i) if (!banned[i]) cand.push_back(i);\n            if (cand.empty()) return -1;\n            return cand[rng.next_int((int)cand.size())];\n        }\n        ld z = rng.uniform() * sum;\n        ld acc = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) {\n            acc += w[i];\n            if (acc >= z) return i;\n        }\n        for (int i = n - 1; i >= 0; --i) if (!banned[i]) return i;\n        return -1;\n    }\n\n    vector<Rect> perturb_from_best(const vector<Rect>& best) {\n        vector<Rect> seed = best;\n        vector<ld> w(n);\n        for (int i = 0; i < n; ++i) {\n            w[i] = 0.01L + (1.0L - satisfaction((ld)rs[i], (ld)best[i].area()));\n        }\n        vector<char> banned(n, 0);\n        int k = 1 + rng.next_int(min(4, n));\n\n        auto reset_rect = [&](int idx) {\n            if (idx < 0) return;\n            seed[idx] = {xs[idx], ys[idx], xs[idx] + 1, ys[idx] + 1};\n            banned[idx] = 1;\n        };\n\n        for (int it = 0; it < k; ++it) {\n            int idx = weighted_pick(w, banned);\n            if (idx < 0) break;\n            reset_rect(idx);\n            if (nearest_idx[idx] != -1 && rng.next_int(100) < 55) {\n                reset_rect(nearest_idx[idx]);\n            }\n        }\n        return seed;\n    }\n\n    ld elapsed_sec() const {\n        return chrono::duration<ld>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void try_update_best(vector<Rect>& cur, ld sc, vector<Rect>& best_rects, ld& best_score) {\n        if (sc > best_score) {\n            best_score = sc;\n            best_rects = cur;\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        xs.resize(n);\n        ys.resize(n);\n        rs.resize(n);\n        sqrs.resize(n);\n\n        uint64_t seed = 1469598103934665603ULL;\n        for (int i = 0; i < n; ++i) {\n            cin >> xs[i] >> ys[i] >> rs[i];\n            sqrs[i] = sqrt((ld)rs[i]);\n            seed ^= (uint64_t)(xs[i] + 1) * 1000003ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(ys[i] + 7) * 1000033ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(rs[i] + 13) * 1000037ULL;\n            seed *= 1099511628211ULL;\n        }\n        rng = XorShift64(seed);\n\n        nearest_idx.assign(n, -1);\n        for (int i = 0; i < n; ++i) {\n            long long bestd = (1LL << 62);\n            for (int j = 0; j < n; ++j) if (i != j) {\n                long long dx = xs[i] - xs[j];\n                long long dy = ys[i] - ys[j];\n                long long d = dx * dx + dy * dy;\n                if (d < bestd) {\n                    bestd = d;\n                    nearest_idx[i] = j;\n                }\n            }\n        }\n\n        start_time = chrono::steady_clock::now();\n\n        vector<Rect> best_rects = initial_rects();\n        ld best_score = total_score(best_rects);\n\n        // Warm-up: some pure greedy seeds.\n        for (int t = 0; t < 2 && elapsed_sec() < 1.5L; ++t) {\n            vector<Rect> cur = initial_rects();\n            Params p = random_constructive_params();\n            ld sc = optimize(cur, p);\n            try_update_best(cur, sc, best_rects, best_score);\n        }\n\n        // Warm-up: some global partition seeds.\n        for (int t = 0; t < 4 && elapsed_sec() < 2.5L; ++t) {\n            vector<Rect> cur = build_partition_solution(random_bsp_params());\n            Params p = random_partition_params();\n            ld sc = optimize(cur, p);\n            try_update_best(cur, sc, best_rects, best_score);\n        }\n\n        int iter = 0;\n        while (elapsed_sec() < 4.75L) {\n            vector<Rect> cur;\n            Params p;\n\n            int mode = iter % 6;\n            if (mode == 0) {\n                cur = initial_rects();\n                p = random_constructive_params();\n            } else if (mode == 1 || mode == 2) {\n                cur = build_partition_solution(random_bsp_params());\n                p = random_partition_params();\n            } else {\n                cur = perturb_from_best(best_rects);\n                p = random_perturb_params();\n            }\n\n            ld sc = optimize(cur, p);\n            try_update_best(cur, sc, best_rects, best_score);\n            ++iter;\n        }\n\n        // Final monotone polish on current best.\n        for (int rep = 0; rep < 2 && elapsed_sec() < 4.92L; ++rep) {\n            vector<Rect> cur = best_rects;\n            Params p = random_partition_params();\n            ld sc = optimize(cur, p);\n            try_update_best(cur, sc, best_rects, best_score);\n        }\n\n        for (int i = 0; i < n; ++i) {\n            cout << best_rects[i].l << ' ' << best_rects[i].b << ' '\n                 << best_rects[i].r << ' ' << best_rects[i].t << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50;\nstatic constexpr int W = 50;\nstatic constexpr int V = H * W;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463325252ull;\n    void seed(uint64_t s) { x = (s ? s : 88172645463325252ull); }\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\nusing Clock = chrono::steady_clock;\n\ninline int id(int i, int j) { return i * W + j; }\n\nstruct CompStat {\n    int tiles;\n    int ub;\n};\n\nstruct Params {\n    int lookDepth = 5;\n    int tilesMargin = 0;\n    int tiles2Margin = 0;\n    int ubMargin = 80;\n    int lookMargin = 8;\n    bool deterministic = false;\n};\n\nstruct Path {\n    vector<int> pos;\n    vector<int> prefixScore;\n    vector<unsigned char> branchCnt;\n    vector<int> branchPoints;\n    int score = 0;\n};\n\nint si, sj, startIdx;\nint tileId[V];\nint pval[V];\nint M;\n\nint adjList[V][4];\nunsigned char adjCnt[V];\n\nvector<int> tileMaxVal;\nvector<unsigned char> usedTile;\nvector<unsigned char> tmpUsed;\n\nint visSq[V];\nvector<int> visTile;\nint bfsStamp = 1;\nint tileStamp = 1;\nint qbuf[V];\n\nvector<int> openingCur, openingBest;\nlong long openingBestVal;\n\ninline bool better_path(const Path& a, const Path& b) {\n    if (a.score != b.score) return a.score > b.score;\n    return a.pos.size() > b.pos.size();\n}\n\ninline CompStat component_stat(int s) {\n    const int st = tileId[s];\n    ++bfsStamp;\n    ++tileStamp;\n\n    int head = 0, tail = 0;\n    qbuf[tail++] = s;\n    visSq[s] = bfsStamp;\n    visTile[st] = tileStamp;\n\n    int tiles = 1;\n    int ub = pval[s];\n\n    while (head < tail) {\n        int u = qbuf[head++];\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            int tv = tileId[v];\n            if (tv == st || usedTile[tv]) continue;\n            if (visSq[v] != bfsStamp) {\n                visSq[v] = bfsStamp;\n                qbuf[tail++] = v;\n            }\n            if (visTile[tv] != tileStamp) {\n                visTile[tv] = tileStamp;\n                ++tiles;\n                ub += tileMaxVal[tv];\n            }\n        }\n    }\n    return {tiles, ub};\n}\n\ninline int degree_after_move(int u) {\n    int cnt = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) ++cnt;\n    }\n    return cnt;\n}\n\nint local_dfs(int u, int depth) {\n    if (depth == 0) return 0;\n\n    struct Cand {\n        int v;\n        int pri;\n    };\n    Cand cand[4];\n    int cnt = 0;\n\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        int tv = tileId[v];\n        if (usedTile[tv]) continue;\n        usedTile[tv] = 1;\n        int deg = degree_after_move(v);\n        usedTile[tv] = 0;\n        // \u4ee5\u524d\u306f\u4f4e\u6b21\u6570\u5bc4\u308a\u3060\u3063\u305f\u304c\u3001\u305d\u308c\u304c\u4e8b\u6545\u8981\u56e0\u306b\u306a\u308a\u3046\u308b\u306e\u3067\u3001\n        // \u4eca\u56de\u306f\u3080\u3057\u308d\u51fa\u53e3\u6570\u3092\u30d7\u30e9\u30b9\u306b\u8a55\u4fa1\u3059\u308b\u3002\n        cand[cnt++] = {v, pval[v] * 8 + deg * 5};\n    }\n    if (cnt == 0) return 0;\n\n    sort(cand, cand + cnt, [](const Cand& a, const Cand& b) {\n        return a.pri > b.pri;\n    });\n\n    int best = 0;\n    for (int i = 0; i < cnt; ++i) {\n        int v = cand[i].v;\n        int tv = tileId[v];\n        usedTile[tv] = 1;\n        int sc = pval[v] + local_dfs(v, depth - 1);\n        usedTile[tv] = 0;\n        if (sc > best) best = sc;\n    }\n    return best;\n}\n\nvoid prepare_path(Path& path) {\n    int n = (int)path.pos.size();\n    path.prefixScore.assign(n, 0);\n    path.branchCnt.assign(n, 0);\n    path.branchPoints.clear();\n\n    fill(tmpUsed.begin(), tmpUsed.end(), 0);\n    int s = 0;\n    for (int i = 0; i < n; ++i) {\n        int u = path.pos[i];\n        tmpUsed[tileId[u]] = 1;\n        s += pval[u];\n        path.prefixScore[i] = s;\n\n        int cnt = 0;\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            if (!tmpUsed[tileId[v]]) ++cnt;\n        }\n        path.branchCnt[i] = (unsigned char)cnt;\n        if (cnt >= 2) path.branchPoints.push_back(i);\n    }\n    path.score = s;\n}\n\nvoid add_elite(vector<Path>& elites, Path cand, int maxKeep = 4) {\n    prepare_path(cand);\n    elites.push_back(std::move(cand));\n    sort(elites.begin(), elites.end(), [](const Path& a, const Path& b) {\n        return better_path(a, b);\n    });\n    if ((int)elites.size() > maxKeep) elites.resize(maxKeep);\n}\n\nint choose_elite(const vector<Path>& elites) {\n    int n = (int)elites.size();\n    int sum = 0;\n    for (int i = 0; i < n; ++i) sum += (n - i);\n    int r = rng.next_int(1, sum);\n    for (int i = 0; i < n; ++i) {\n        r -= (n - i);\n        if (r <= 0) return i;\n    }\n    return 0;\n}\n\nint choose_cut(const Path& path) {\n    if (path.branchPoints.empty()) return 0;\n    const auto& bp = path.branchPoints;\n    int n = (int)bp.size();\n\n    int l = 0, r = n - 1;\n    if (n >= 3) {\n        int a = n / 3;\n        int b = (2 * n) / 3;\n        double x = rng.next_double();\n        if (x < 0.20) {\n            l = 0;\n            r = max(0, a - 1);\n        } else if (x < 0.60) {\n            l = a;\n            r = max(a, b - 1);\n        } else {\n            l = b;\n            r = n - 1;\n        }\n    }\n    return bp[l + rng.next_int(0, r - l)];\n}\n\nstruct MoveInfo {\n    int v = -1;\n    int tiles1 = 0;\n    int ub1 = 0;\n    int tiles2 = -1;\n    int ub2 = -1;\n    int look = -1;\n    int deg = -1;\n};\n\ninline bool better_move_safe(const MoveInfo& a, const MoveInfo& b) {\n    if (a.tiles1 != b.tiles1) return a.tiles1 > b.tiles1;\n    if (a.tiles2 != b.tiles2) return a.tiles2 > b.tiles2;\n    if (a.ub1 != b.ub1) return a.ub1 > b.ub1;\n    if (a.ub2 != b.ub2) return a.ub2 > b.ub2;\n    if (a.look != b.look) return a.look > b.look;\n    if (a.deg != b.deg) return a.deg > b.deg;\n    return pval[a.v] > pval[b.v];\n}\n\ninline void ensure_deg_second(MoveInfo& info, bool need2) {\n    if (info.deg != -1 && (!need2 || info.tiles2 != -1)) return;\n\n    int v = info.v;\n    int tv = tileId[v];\n    usedTile[tv] = 1;\n\n    if (info.deg == -1) info.deg = degree_after_move(v);\n\n    if (need2 && info.tiles2 == -1) {\n        int bestT2 = 0;\n        int bestU2 = 0;\n        for (int k = 0; k < adjCnt[v]; ++k) {\n            int w = adjList[v][k];\n            int tw = tileId[w];\n            if (usedTile[tw]) continue;\n            auto cs = component_stat(w);\n            if (cs.tiles > bestT2 || (cs.tiles == bestT2 && cs.ub > bestU2)) {\n                bestT2 = cs.tiles;\n                bestU2 = cs.ub;\n            }\n        }\n        info.tiles2 = bestT2;\n        info.ub2 = bestU2;\n    }\n\n    usedTile[tv] = 0;\n}\n\ninline void ensure_look(MoveInfo& info, int depth, bool need2) {\n    if (info.look != -1) return;\n\n    int v = info.v;\n    int tv = tileId[v];\n    usedTile[tv] = 1;\n\n    if (info.deg == -1) info.deg = degree_after_move(v);\n\n    if (need2 && info.tiles2 == -1) {\n        int bestT2 = 0;\n        int bestU2 = 0;\n        for (int k = 0; k < adjCnt[v]; ++k) {\n            int w = adjList[v][k];\n            int tw = tileId[w];\n            if (usedTile[tw]) continue;\n            auto cs = component_stat(w);\n            if (cs.tiles > bestT2 || (cs.tiles == bestT2 && cs.ub > bestU2)) {\n                bestT2 = cs.tiles;\n                bestU2 = cs.ub;\n            }\n        }\n        info.tiles2 = bestT2;\n        info.ub2 = bestU2;\n    }\n\n    info.look = pval[v] + local_dfs(v, max(0, depth - 1));\n    usedTile[tv] = 0;\n}\n\nParams random_params(bool restart) {\n    Params p;\n    p.lookDepth = restart ? 5 + rng.next_int(0, 1) : 4 + rng.next_int(0, 2);\n    p.tilesMargin = (rng.next_double() < 0.65 ? 0 : 1);\n    p.tiles2Margin = (rng.next_double() < 0.70 ? 0 : 1);\n    p.ubMargin = 50 + rng.next_int(0, 100);\n    p.lookMargin = 5 + rng.next_int(0, 10);\n    p.deterministic = false;\n    return p;\n}\n\nPath build_path(vector<int> pos, int score, const Params& prm, const Clock::time_point& deadline) {\n    Path res;\n    res.pos = std::move(pos);\n    res.score = score;\n    res.pos.reserve(V);\n\n    int stepCounter = 0;\n    int suffixStep = 0;\n\n    while (true) {\n        if ((stepCounter++ & 31) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n\n        int u = res.pos.back();\n        int cand[4];\n        int ccnt = 0;\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            if (!usedTile[tileId[v]]) cand[ccnt++] = v;\n        }\n        if (ccnt == 0) break;\n        if (ccnt == 1) {\n            int v = cand[0];\n            usedTile[tileId[v]] = 1;\n            res.pos.push_back(v);\n            res.score += pval[v];\n            ++suffixStep;\n            continue;\n        }\n\n        MoveInfo info[4];\n        int maxT1 = -1, secondT1 = -1;\n        for (int i = 0; i < ccnt; ++i) {\n            auto cs = component_stat(cand[i]);\n            info[i].v = cand[i];\n            info[i].tiles1 = cs.tiles;\n            info[i].ub1 = cs.ub;\n            if (cs.tiles > maxT1) {\n                secondT1 = maxT1;\n                maxT1 = cs.tiles;\n            } else if (cs.tiles > secondT1) {\n                secondT1 = cs.tiles;\n            }\n        }\n\n        bool need2 = prm.deterministic || suffixStep < 20;\n        if (!need2 && maxT1 - secondT1 <= 1) need2 = true;\n\n        if (need2) {\n            for (int i = 0; i < ccnt; ++i) ensure_deg_second(info[i], true);\n        }\n\n        int depth = prm.lookDepth;\n        if (suffixStep < 6) depth += 2;\n        else if (suffixStep < 16) depth += 1;\n        depth = min(depth, 8);\n\n        int chosen = info[0].v;\n\n        // \u5e8f\u76e4\u306f\u4e8b\u6545\u9632\u6b62\u306e\u305f\u3081 deterministic \u306b\u5b89\u5168\u91cd\u8996\u3002\n        if (prm.deterministic || suffixStep < 12) {\n            for (int i = 0; i < ccnt; ++i) ensure_look(info[i], depth, need2);\n            int bestIdx = 0;\n            for (int i = 1; i < ccnt; ++i) {\n                if (better_move_safe(info[i], info[bestIdx])) bestIdx = i;\n            }\n            chosen = info[bestIdx].v;\n        } else {\n            int alive[4];\n            int acnt = 0;\n            for (int i = 0; i < ccnt; ++i) alive[acnt++] = i;\n\n            int bestT = -1;\n            for (int i = 0; i < acnt; ++i) bestT = max(bestT, info[alive[i]].tiles1);\n            {\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].tiles1 >= bestT - prm.tilesMargin) nxt[ncnt++] = idx;\n                }\n                memcpy(alive, nxt, sizeof(int) * ncnt);\n                acnt = ncnt;\n            }\n\n            if (need2 && acnt >= 2) {\n                int bestT2 = -1;\n                for (int i = 0; i < acnt; ++i) bestT2 = max(bestT2, info[alive[i]].tiles2);\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].tiles2 >= bestT2 - prm.tiles2Margin) nxt[ncnt++] = idx;\n                }\n                memcpy(alive, nxt, sizeof(int) * ncnt);\n                acnt = ncnt;\n            }\n\n            if (acnt >= 2) {\n                int bestU = -1;\n                for (int i = 0; i < acnt; ++i) bestU = max(bestU, info[alive[i]].ub1);\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].ub1 >= bestU - prm.ubMargin) nxt[ncnt++] = idx;\n                }\n                memcpy(alive, nxt, sizeof(int) * ncnt);\n                acnt = ncnt;\n            }\n\n            for (int i = 0; i < acnt; ++i) ensure_look(info[alive[i]], depth, need2);\n\n            int bestLook = -1;\n            for (int i = 0; i < acnt; ++i) bestLook = max(bestLook, info[alive[i]].look);\n\n            int finalIdx[4], fcnt = 0;\n            int weights[4], wsum = 0;\n            for (int i = 0; i < acnt; ++i) {\n                int idx = alive[i];\n                if (info[idx].look >= bestLook - prm.lookMargin) {\n                    finalIdx[fcnt] = idx;\n                    int w = info[idx].look - (bestLook - prm.lookMargin) + 1;\n                    w += info[idx].deg * 2; // \u51fa\u53e3\u304c\u591a\u3044\u65b9\u3092\u5c11\u3057\u512a\u9047\n                    if (w < 1) w = 1;\n                    weights[fcnt] = w;\n                    wsum += w;\n                    ++fcnt;\n                }\n            }\n\n            // \u307e\u3060\u8907\u6570\u306a\u3089\u82e5\u5e72\u30e9\u30f3\u30c0\u30e0\u306b\u3002\n            int r = rng.next_int(1, wsum);\n            chosen = info[finalIdx[0]].v;\n            for (int i = 0; i < fcnt; ++i) {\n                r -= weights[i];\n                if (r <= 0) {\n                    chosen = info[finalIdx[i]].v;\n                    break;\n                }\n            }\n        }\n\n        usedTile[tileId[chosen]] = 1;\n        res.pos.push_back(chosen);\n        res.score += pval[chosen];\n        ++suffixStep;\n    }\n\n    return res;\n}\n\n// \u5e8f\u76e4\u3060\u3051\u6df1\u304f\u8aad\u3080 prefix \u63a2\u7d22\u3002\n// \u3053\u3053\u3067\u4e8b\u6545\u3092\u6e1b\u3089\u3059\u3002\nvoid opening_dfs(int u, int depth, long long acc) {\n    if (depth == 0) {\n        auto cs = component_stat(u);\n        long long remUB = cs.ub - pval[u];\n        long long remTiles = cs.tiles - 1;\n        long long val = acc * 256LL + remUB * 3LL + remTiles * 40LL;\n        if (val > openingBestVal) {\n            openingBestVal = val;\n            openingBest = openingCur;\n        }\n        return;\n    }\n\n    struct Cand {\n        int v;\n        int tiles;\n        int ub;\n        int deg;\n    };\n    Cand cand[4];\n    int cnt = 0;\n\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        int tv = tileId[v];\n        if (usedTile[tv]) continue;\n\n        auto cs = component_stat(v);\n        usedTile[tv] = 1;\n        int deg = degree_after_move(v);\n        usedTile[tv] = 0;\n\n        cand[cnt++] = {v, cs.tiles, cs.ub, deg};\n    }\n\n    if (cnt == 0) {\n        auto cs = component_stat(u);\n        long long remUB = cs.ub - pval[u];\n        long long remTiles = cs.tiles - 1;\n        long long val = acc * 256LL + remUB * 3LL + remTiles * 40LL;\n        if (val > openingBestVal) {\n            openingBestVal = val;\n            openingBest = openingCur;\n        }\n        return;\n    }\n\n    sort(cand, cand + cnt, [](const Cand& a, const Cand& b) {\n        if (a.tiles != b.tiles) return a.tiles > b.tiles;\n        if (a.ub != b.ub) return a.ub > b.ub;\n        if (a.deg != b.deg) return a.deg > b.deg;\n        return pval[a.v] > pval[b.v];\n    });\n\n    for (int i = 0; i < cnt; ++i) {\n        int v = cand[i].v;\n        int tv = tileId[v];\n        usedTile[tv] = 1;\n        openingCur.push_back(v);\n        opening_dfs(v, depth - 1, acc + pval[v]);\n        openingCur.pop_back();\n        usedTile[tv] = 0;\n    }\n}\n\nstring to_answer(const vector<int>& pos) {\n    string ans;\n    if (pos.size() <= 1) return ans;\n    ans.reserve(pos.size() - 1);\n    for (size_t i = 1; i < pos.size(); ++i) {\n        int d = pos[i] - pos[i - 1];\n        if (d == -W) ans.push_back('U');\n        else if (d == W) ans.push_back('D');\n        else if (d == -1) ans.push_back('L');\n        else if (d == 1) ans.push_back('R');\n    }\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj;\n    startIdx = id(si, sj);\n\n    int maxTile = -1;\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int t;\n            cin >> t;\n            tileId[id(i, j)] = t;\n            maxTile = max(maxTile, t);\n        }\n    }\n    M = maxTile + 1;\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            cin >> pval[id(i, j)];\n        }\n    }\n\n    tileMaxVal.assign(M, 0);\n    for (int v = 0; v < V; ++v) {\n        tileMaxVal[tileId[v]] = max(tileMaxVal[tileId[v]], pval[v]);\n    }\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int u = id(i, j);\n            int cnt = 0;\n            const int di[4] = {-1, 1, 0, 0};\n            const int dj[4] = {0, 0, -1, 1};\n            for (int dir = 0; dir < 4; ++dir) {\n                int ni = i + di[dir];\n                int nj = j + dj[dir];\n                if (ni < 0 || ni >= H || nj < 0 || nj >= W) continue;\n                int v = id(ni, nj);\n                if (tileId[v] == tileId[u]) continue;\n                adjList[u][cnt++] = v;\n            }\n            adjCnt[u] = (unsigned char)cnt;\n        }\n    }\n\n    usedTile.assign(M, 0);\n    tmpUsed.assign(M, 0);\n    visTile.assign(M, 0);\n    memset(visSq, 0, sizeof(visSq));\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)startIdx + 0x9e3779b97f4a7c15ull;\n    for (int v = 0; v < V; ++v) {\n        seed = seed * 1000003ull ^ (uint64_t)(tileId[v] + 1);\n        seed = seed * 1000003ull ^ (uint64_t)(pval[v] + 7);\n    }\n    rng.seed(seed);\n\n    auto deadline = Clock::now() + chrono::milliseconds(1950);\n\n    vector<Path> elites;\n\n    // 1) deterministic \u306a\u4fdd\u967a\u89e3\u3092\u307e\u305a\u4f5c\u308b\n    fill(usedTile.begin(), usedTile.end(), 0);\n    usedTile[tileId[startIdx]] = 1;\n\n    openingCur.clear();\n    openingBest.clear();\n    openingBestVal = -(1LL << 60);\n    opening_dfs(startIdx, 7, 0);  // \u5e8f\u76e4\u3060\u3051\u5c11\u3057\u6df1\u3081\u306b\u63a2\u7d22\n\n    vector<int> prefix;\n    prefix.reserve(V);\n    prefix.push_back(startIdx);\n    int prefScore = pval[startIdx];\n    for (int v : openingBest) {\n        prefix.push_back(v);\n        prefScore += pval[v];\n        usedTile[tileId[v]] = 1;\n    }\n\n    Params safe;\n    safe.lookDepth = 6;\n    safe.tilesMargin = 0;\n    safe.tiles2Margin = 0;\n    safe.ubMargin = 0;\n    safe.lookMargin = 0;\n    safe.deterministic = true;\n\n    Path base = build_path(prefix, prefScore, safe, deadline);\n    add_elite(elites, std::move(base));\n\n    // 2) \u3082\u30461\u672c\u3001\u6700\u521d\u304b\u3089 deterministic \u3067\u4f5c\u308b\n    if (Clock::now() < deadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        vector<int> p2 = {startIdx};\n        Params safe2 = safe;\n        safe2.lookDepth = 5;\n        Path base2 = build_path(p2, pval[startIdx], safe2, deadline);\n        add_elite(elites, std::move(base2));\n    }\n\n    // 3) elite \u304b\u3089 suffix \u518d\u69cb\u7bc9 / restart \u3092\u7e70\u308a\u8fd4\u3059\n    while (Clock::now() < deadline) {\n        bool restart = elites.empty() || (rng.next_double() < 0.22);\n        const Path* src = nullptr;\n\n        fill(usedTile.begin(), usedTile.end(), 0);\n        vector<int> pref;\n        int score = 0;\n\n        if (!restart) {\n            int ei = choose_elite(elites);\n            src = &elites[ei];\n            if (src->branchPoints.empty()) restart = true;\n        }\n\n        if (restart) {\n            pref = {startIdx};\n            score = pval[startIdx];\n            usedTile[tileId[startIdx]] = 1;\n        } else {\n            int cut = choose_cut(*src);\n            pref.assign(src->pos.begin(), src->pos.begin() + cut + 1);\n            score = src->prefixScore[cut];\n            for (int i = 0; i <= cut; ++i) {\n                usedTile[tileId[src->pos[i]]] = 1;\n            }\n        }\n\n        Params prm = random_params(restart);\n        Path cand = build_path(std::move(pref), score, prm, deadline);\n        add_elite(elites, std::move(cand));\n    }\n\n    if (elites.empty()) {\n        cout << '\\n';\n        return 0;\n    }\n\n    cout << to_answer(elites[0].pos) << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int HN = N * (N - 1);     // 30 * 29 = 870\nstatic constexpr int VN = (N - 1) * N;     // 29 * 30 = 870\nstatic constexpr int E = HN + VN;          // 1740\nstatic constexpr double INIT_COST = 5000.0;\nstatic constexpr double MIN_COST = 1000.0;\nstatic constexpr double MAX_COST = 9000.0;\n\ninline int hid(int i, int j) { return i * 29 + j; }          // h[i][j], 0<=i<30, 0<=j<29\ninline int vid(int i, int j) { return HN + i * 30 + j; }     // v[i][j], 0<=i<29, 0<=j<30\ninline int node_id(int i, int j) { return i * N + j; }\n\nstruct Observation {\n    vector<int> edges;\n    double y;\n    double w; // weight = 1 / path_length\n};\n\nstruct Path {\n    string s;\n    vector<int> edges;\n    double raw_cost = 0.0; // sum of current estimated edge costs (without any search penalty)\n};\n\nstruct Solver {\n    vector<double> x;          // current edge estimates\n    vector<int> vis;           // how many times each edge has been used\n    vector<Observation> hist;  // past observations\n\n    mt19937 rng;\n\n    Solver() : x(E, INIT_COST), vis(E, 0) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        hist.reserve(1000);\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    int randint(int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    }\n\n    double exploration_score(const Path& p, double bonus) const {\n        double score = p.raw_cost;\n        for (int e : p.edges) {\n            score -= bonus / sqrt((double)vis[e] + 1.0);\n        }\n        return score;\n    }\n\n    Path random_monotone_path(int si, int sj, int ti, int tj) {\n        Path p;\n        int i = si, j = sj;\n        int rv = abs(ti - si);\n        int rh = abs(tj - sj);\n        char mv_v = (ti > si ? 'D' : 'U');\n        char mv_h = (tj > sj ? 'R' : 'L');\n\n        p.s.reserve(rv + rh);\n        p.edges.reserve(rv + rh);\n\n        while (rv > 0 || rh > 0) {\n            bool take_v;\n            if (rv == 0) take_v = false;\n            else if (rh == 0) take_v = true;\n            else take_v = (randint(1, rv + rh) <= rv);\n\n            if (take_v) {\n                if (mv_v == 'D') {\n                    int e = vid(i, j);\n                    p.s.push_back('D');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    ++i;\n                } else {\n                    int e = vid(i - 1, j);\n                    p.s.push_back('U');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    --i;\n                }\n                --rv;\n            } else {\n                if (mv_h == 'R') {\n                    int e = hid(i, j);\n                    p.s.push_back('R');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    ++j;\n                } else {\n                    int e = hid(i, j - 1);\n                    p.s.push_back('L');\n                    p.edges.push_back(e);\n                    p.raw_cost += x[e];\n                    --j;\n                }\n                --rh;\n            }\n        }\n        return p;\n    }\n\n    Path dijkstra_path(int si, int sj, int ti, int tj, double step_penalty) const {\n        const int V = N * N;\n        const double INF = 1e100;\n\n        vector<double> dist(V, INF);\n        vector<int> parent(V, -1), parent_edge(V, -1);\n        vector<char> parent_char(V, '?');\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        int s = node_id(si, sj);\n        int t = node_id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        auto relax = [&](int v, int ni, int nj, int e, char c, double w) {\n            int nv = node_id(ni, nj);\n            double nd = dist[v] + w;\n            if (nd + 1e-12 < dist[nv]) {\n                dist[nv] = nd;\n                parent[nv] = v;\n                parent_edge[nv] = e;\n                parent_char[nv] = c;\n                pq.push({nd, nv});\n            }\n        };\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d > dist[v] + 1e-12) continue;\n            if (v == t) break;\n\n            int i = v / N;\n            int j = v % N;\n\n            if (i > 0) {\n                int e = vid(i - 1, j);\n                relax(v, i - 1, j, e, 'U', x[e] + step_penalty);\n            }\n            if (i + 1 < N) {\n                int e = vid(i, j);\n                relax(v, i + 1, j, e, 'D', x[e] + step_penalty);\n            }\n            if (j > 0) {\n                int e = hid(i, j - 1);\n                relax(v, i, j - 1, e, 'L', x[e] + step_penalty);\n            }\n            if (j + 1 < N) {\n                int e = hid(i, j);\n                relax(v, i, j + 1, e, 'R', x[e] + step_penalty);\n            }\n        }\n\n        Path res;\n        vector<char> rs;\n        vector<int> re;\n\n        for (int cur = t; cur != s; cur = parent[cur]) {\n            rs.push_back(parent_char[cur]);\n            re.push_back(parent_edge[cur]);\n        }\n        reverse(rs.begin(), rs.end());\n        reverse(re.begin(), re.end());\n\n        res.s.assign(rs.begin(), rs.end());\n        res.edges = move(re);\n        res.raw_cost = 0.0;\n        for (int e : res.edges) res.raw_cost += x[e];\n        return res;\n    }\n\n    static double dot_vec(const vector<double>& a, const vector<double>& b) {\n        double s = 0.0;\n        for (int i = 0; i < (int)a.size(); ++i) s += a[i] * b[i];\n        return s;\n    }\n\n    void fit_piecewise_29(const array<double, 29>& val,\n                          const array<double, 29>& wt,\n                          array<double, 29>& out) {\n        array<double, 30> W{}, S{}, Q{};\n        for (int i = 0; i < 29; ++i) {\n            W[i + 1] = W[i] + wt[i];\n            S[i + 1] = S[i] + wt[i] * val[i];\n            Q[i + 1] = Q[i] + wt[i] * val[i] * val[i];\n        }\n\n        auto seg = [&](int l, int r) -> pair<double, double> {\n            double w = W[r + 1] - W[l];\n            double s = S[r + 1] - S[l];\n            double q = Q[r + 1] - Q[l];\n            double mean = s / max(w, 1e-9);\n            double err = q - s * s / max(w, 1e-9);\n            return {mean, err};\n        };\n\n        auto [m1, e1] = seg(0, 28);\n\n        double best2 = 1e100;\n        int bestk = -1;\n        double ml = m1, mr = m1;\n        for (int k = 1; k <= 28; ++k) {\n            auto [a, ea] = seg(0, k - 1);\n            auto [b, eb] = seg(k, 28);\n            double tot = ea + eb;\n            if (tot < best2) {\n                best2 = tot;\n                bestk = k;\n                ml = a;\n                mr = b;\n            }\n        }\n\n        bool use_one = false;\n        if (bestk == -1) use_one = true;\n        if (best2 > e1 * 0.94) use_one = true;\n        if (fabs(ml - mr) < 150.0) use_one = true;\n\n        if (use_one) {\n            for (int i = 0; i < 29; ++i) out[i] = m1;\n        } else {\n            for (int i = 0; i < bestk; ++i) out[i] = ml;\n            for (int i = bestk; i < 29; ++i) out[i] = mr;\n        }\n    }\n\n    void piecewise_project() {\n        // Horizontal rows\n        for (int i = 0; i < 30; ++i) {\n            array<double, 29> val{}, wt{}, tgt{};\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                val[j] = x[e];\n                wt[j] = vis[e] + 3.0;\n            }\n            fit_piecewise_29(val, wt, tgt);\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                double beta = min(0.30, 0.45 / sqrt((double)vis[e] + 2.0));\n                x[e] = clamp((1.0 - beta) * x[e] + beta * tgt[j], MIN_COST, MAX_COST);\n            }\n        }\n\n        // Vertical columns\n        for (int j = 0; j < 30; ++j) {\n            array<double, 29> val{}, wt{}, tgt{};\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                val[i] = x[e];\n                wt[i] = vis[e] + 3.0;\n            }\n            fit_piecewise_29(val, wt, tgt);\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                double beta = min(0.30, 0.45 / sqrt((double)vis[e] + 2.0));\n                x[e] = clamp((1.0 - beta) * x[e] + beta * tgt[i], MIN_COST, MAX_COST);\n            }\n        }\n    }\n\n    void global_refine() {\n        int nobs = (int)hist.size();\n        if (nobs == 0) return;\n\n        // Regularization decays slightly as more observations accumulate.\n        double lambda0 = 0.10 / sqrt(nobs + 1.0) + 0.015; // weak prior to 5000\n        double lambda1 = 0.35 / sqrt(nobs + 1.0) + 0.035; // smoothness along rows/columns\n\n        vector<double> rhs(E, lambda0 * INIT_COST);\n        for (const auto& ob : hist) {\n            double c = ob.w * ob.y;\n            for (int e : ob.edges) rhs[e] += c;\n        }\n\n        auto apply = [&](const vector<double>& p, vector<double>& out) {\n            out.assign(E, 0.0);\n\n            // prior\n            for (int e = 0; e < E; ++e) out[e] = lambda0 * p[e];\n\n            // data term: sum w * a a^T p\n            for (const auto& ob : hist) {\n                double s = 0.0;\n                for (int e : ob.edges) s += p[e];\n                s *= ob.w;\n                for (int e : ob.edges) out[e] += s;\n            }\n\n            // smoothness along horizontal rows\n            for (int i = 0; i < 30; ++i) {\n                for (int j = 0; j < 28; ++j) {\n                    int e1 = hid(i, j);\n                    int e2 = hid(i, j + 1);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n\n            // smoothness along vertical columns\n            for (int j = 0; j < 30; ++j) {\n                for (int i = 0; i < 28; ++i) {\n                    int e1 = vid(i, j);\n                    int e2 = vid(i + 1, j);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n        };\n\n        vector<double> sol = x, r(E), p(E), Ap(E);\n        apply(sol, Ap);\n        for (int e = 0; e < E; ++e) r[e] = rhs[e] - Ap[e];\n        p = r;\n\n        double rs0 = dot_vec(r, r);\n        double rs = rs0;\n        if (rs < 1e-12) return;\n\n        const int ITERS = 25;\n        for (int it = 0; it < ITERS; ++it) {\n            apply(p, Ap);\n            double pAp = dot_vec(p, Ap);\n            if (pAp <= 1e-18) break;\n            double alpha = rs / pAp;\n\n            for (int e = 0; e < E; ++e) sol[e] += alpha * p[e];\n            for (int e = 0; e < E; ++e) r[e] -= alpha * Ap[e];\n\n            double rs_new = dot_vec(r, r);\n            if (rs_new < rs0 * 1e-10) break;\n\n            double beta = rs_new / rs;\n            for (int e = 0; e < E; ++e) p[e] = r[e] + beta * p[e];\n            rs = rs_new;\n        }\n\n        for (int e = 0; e < E; ++e) x[e] = clamp(sol[e], MIN_COST, MAX_COST);\n\n        // Extra projection exploiting M in {1,2}\n        piecewise_project();\n    }\n\n    void online_update(const Path& path, double y, int qidx) {\n        const int m = (int)path.edges.size();\n        if (m == 0) return;\n\n        double pred = path.raw_cost;\n        double residual = y - pred;\n\n        double eta;\n        if (qidx < 120) eta = 0.35;\n        else if (qidx < 350) eta = 0.24;\n        else eta = 0.18;\n\n        vector<double> u(m);\n        double su = 0.0;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            u[k] = 1.0 / sqrt((double)vis[e] + 1.0);\n            su += u[k];\n        }\n        if (su < 1e-12) su = 1.0;\n\n        double scale = eta * residual / su;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            double delta = scale * u[k];\n            delta = clamp(delta, -1000.0, 1000.0);\n            x[e] = clamp(x[e] + delta, MIN_COST, MAX_COST);\n        }\n        for (int e : path.edges) vis[e]++;\n\n        hist.push_back({path.edges, y, 1.0 / m});\n    }\n\n    Path choose_path(int si, int sj, int ti, int tj, int qidx) {\n        bool explore = false;\n        double bonus = 0.0;\n        int samples = 0;\n\n        if (qidx < 150) {\n            explore = true;\n            bonus = 260.0;\n            samples = 24;\n        } else if (qidx < 400 && rand01() < 0.06) {\n            explore = true;\n            bonus = 120.0;\n            samples = 10;\n        }\n\n        double step_penalty = 300.0 * max(0.0, 1.0 - qidx / 500.0);\n\n        if (!explore) {\n            return dijkstra_path(si, sj, ti, tj, step_penalty);\n        }\n\n        Path best = random_monotone_path(si, sj, ti, tj);\n        double best_score = exploration_score(best, bonus);\n\n        for (int t = 1; t < samples; ++t) {\n            Path cand = random_monotone_path(si, sj, ti, tj);\n            double sc = exploration_score(cand, bonus);\n            if (sc < best_score || (fabs(sc - best_score) < 1e-9 && randint(0, 1))) {\n                best = move(cand);\n                best_score = sc;\n            }\n        }\n\n        Path dijk = dijkstra_path(si, sj, ti, tj, step_penalty);\n        double dsc = exploration_score(dijk, bonus);\n        if (dsc < best_score) best = move(dijk);\n\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        Path path = solver.choose_path(si, sj, ti, tj, q);\n\n        cout << path.s << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.online_update(path, (double)result, q);\n\n        bool do_refine = false;\n        int qq = q + 1;\n        if (qq <= 200) {\n            if (qq % 20 == 0) do_refine = true;\n        } else {\n            if (qq % 40 == 0) do_refine = true;\n        }\n\n        if (do_refine) {\n            solver.global_refine();\n        }\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nusing Matrix = array<unsigned char, N * N>;\n\nstruct Candidate {\n    string row;\n    vector<int> cover;   // unique string ids\n    int totalWeight = 0;\n};\n\nstruct Move {\n    long long val;\n    string s;\n};\n\nstruct Edge {\n    int pid;\n    unsigned char req;\n};\n\nstatic chrono::steady_clock::time_point gStart;\nstatic inline long long elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - gStart\n    ).count();\n}\n\nmt19937 rng((unsigned)chrono::steady_clock::now().time_since_epoch().count());\n\n// compressed input\nvector<string> pats;\nvector<vector<unsigned char>> pch;\nvector<int> wt;\nvector<int> impOrder;\n\n// exact local-search graph\nvector<vector<Edge>> cellEdges;  // 400 cells\nvector<int> plSid;\nvector<unsigned char> plLen;\nvector<unsigned char> plMatch;\n\n// ---------- utilities for row candidate generation ----------\n\ninline bool contains_in_doubled(const char* dd, const string& p) {\n    const int k = (int)p.size();\n    const char* ps = p.data();\n    for (int st = 0; st < N; ++st) {\n        int j = 0;\n        while (j < k && dd[st + j] == ps[j]) ++j;\n        if (j == k) return true;\n    }\n    return false;\n}\n\nint overlap_suffix_prefix(const string& a, const string& b) {\n    int lim = min((int)a.size(), (int)b.size());\n    for (int o = lim; o >= 1; --o) {\n        bool ok = true;\n        int sa = (int)a.size() - o;\n        for (int i = 0; i < o; ++i) {\n            if (a[sa + i] != b[i]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) return o;\n    }\n    return 0;\n}\n\nstring repeat_to_20(const string& s) {\n    if ((int)s.size() == N) return s;\n    string r(N, 'A');\n    for (int i = 0; i < N; ++i) r[i] = s[i % (int)s.size()];\n    return r;\n}\n\nstring min_rotation(const string& s) {\n    string best = s;\n    for (int sh = 1; sh < N; ++sh) {\n        string t = s.substr(sh) + s.substr(0, sh);\n        if (t < best) best = t;\n    }\n    return best;\n}\n\nvoid push_top(vector<Move>& top, long long val, const string& s, int cap = 4) {\n    if (val <= 0) return;\n    top.push_back({val, s});\n    int pos = (int)top.size() - 1;\n    while (pos > 0 && top[pos].val > top[pos - 1].val) {\n        swap(top[pos], top[pos - 1]);\n        --pos;\n    }\n    if ((int)top.size() > cap) top.pop_back();\n}\n\nstring choose_move(const vector<Move>& top, bool randomized) {\n    if (top.empty()) return \"\";\n    if (!randomized || top.size() == 1) return top[0].s;\n    int k = min<int>(3, top.size());\n    int r = (int)(rng() % 10);\n    int idx = 0;\n    if (k >= 3) {\n        if (r < 6) idx = 0;\n        else if (r < 9) idx = 1;\n        else idx = 2;\n    } else if (k == 2) {\n        idx = (r < 7 ? 0 : 1);\n    }\n    return top[idx].s;\n}\n\nstring build_candidate_row(int seedId, bool randomized) {\n    string cur = pats[seedId];\n    int scanLim = min<int>((int)impOrder.size(), 220);\n\n    // phase 0: strong overlap/containment\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            if ((int)x.size() > (int)cur.size()) {\n                if (x.find(cur) != string::npos && (int)x.size() <= N) {\n                    long long val = 1LL * wt[id] * 3000 + 1LL * ((int)x.size() - (int)cur.size()) * 200;\n                    push_top(top, val, x);\n                }\n            }\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty()) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    // phase 1: pack more useful strings\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty() || top[0].val <= 0) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    return repeat_to_20(cur);\n}\n\nvector<string> build_initial_rows(const vector<int>& charFreq) {\n    int U = (int)pats.size();\n    vector<Candidate> cands;\n    cands.reserve(300);\n\n    unordered_set<string> seen;\n    seen.reserve(1024);\n\n    auto add_candidate = [&](string row) {\n        if ((int)row.size() != N) row = repeat_to_20(row);\n        row = min_rotation(row);\n        if (!seen.insert(row).second) return;\n\n        char dd[40];\n        for (int i = 0; i < N; ++i) dd[i] = dd[i + N] = row[i];\n\n        Candidate cand;\n        cand.row = row;\n        cand.totalWeight = 0;\n        for (int id = 0; id < U; ++id) {\n            if (contains_in_doubled(dd, pats[id])) {\n                cand.cover.push_back(id);\n                cand.totalWeight += wt[id];\n            }\n        }\n        if (!cand.cover.empty()) cands.push_back(std::move(cand));\n    };\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n\n    // constant rows\n    for (int c = 0; c < 8; ++c) add_candidate(string(N, char('A' + c)));\n\n    // repeated strong seeds\n    for (int t = 0; t < min(U, 60); ++t) {\n        add_candidate(repeat_to_20(pats[impOrder[t]]));\n    }\n\n    // deterministic builds\n    for (int t = 0; t < min(U, 70); ++t) {\n        add_candidate(build_candidate_row(impOrder[t], false));\n        if (elapsed_ms() > 650) break;\n    }\n\n    // randomized builds\n    for (int t = 0; t < 35; ++t) {\n        int lim = min(U, max(1, 40 + t));\n        int seedId = impOrder[(int)(rng() % lim)];\n        add_candidate(build_candidate_row(seedId, true));\n        if (elapsed_ms() > 850) break;\n    }\n\n    // fallback patterns\n    if ((int)cands.size() < 20) {\n        for (int a = 0; a < 8; ++a) {\n            for (int b = 0; b < 8; ++b) {\n                string s(N, 'A');\n                for (int i = 0; i < N; ++i) s[i] = char('A' + ((i & 1) ? b : a));\n                add_candidate(s);\n                if ((int)cands.size() >= 20) break;\n            }\n            if ((int)cands.size() >= 20) break;\n        }\n    }\n\n    if (cands.empty()) {\n        vector<string> rows(20, string(N, char('A' + bestChar)));\n        return rows;\n    }\n\n    int C = (int)cands.size();\n\n    // greedy set cover\n    vector<int> selected;\n    selected.reserve(20);\n    vector<char> usedCand(C, 0);\n    vector<char> covered(U, 0);\n\n    for (int step = 0; step < 20 && step < C; ++step) {\n        int best = -1;\n        long long bestGain = -1;\n        int bestTotal = -1;\n        for (int ci = 0; ci < C; ++ci) if (!usedCand[ci]) {\n            long long gain = 0;\n            for (int id : cands[ci].cover) if (!covered[id]) gain += wt[id];\n            if (gain > bestGain || (gain == bestGain && cands[ci].totalWeight > bestTotal)) {\n                bestGain = gain;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n        if (best == -1) break;\n        usedCand[best] = 1;\n        selected.push_back(best);\n        for (int id : cands[best].cover) covered[id] = 1;\n    }\n\n    if ((int)selected.size() < 20) {\n        vector<int> ord(C);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return cands[a].totalWeight > cands[b].totalWeight;\n        });\n        for (int ci : ord) {\n            if ((int)selected.size() >= 20) break;\n            if (!usedCand[ci]) {\n                usedCand[ci] = 1;\n                selected.push_back(ci);\n            }\n        }\n    }\n    while ((int)selected.size() < 20) selected.push_back(selected[0]);\n\n    // one replacement-improvement pass\n    vector<int> coverCnt(U, 0);\n    long long rowWeight = 0;\n    fill(usedCand.begin(), usedCand.end(), 0);\n    for (int ci : selected) usedCand[ci] = 1;\n    for (int ci : selected) {\n        for (int id : cands[ci].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    for (int pos = 0; pos < 20; ++pos) {\n        int old = selected[pos];\n        usedCand[old] = 0;\n        for (int id : cands[old].cover) {\n            if (--coverCnt[id] == 0) rowWeight -= wt[id];\n        }\n\n        int best = old;\n        long long bestScore = rowWeight;\n        int bestTotal = cands[old].totalWeight;\n\n        for (int ci = 0; ci < C; ++ci) {\n            if (usedCand[ci]) continue;\n            long long sc = rowWeight;\n            for (int id : cands[ci].cover) {\n                if (coverCnt[id] == 0) sc += wt[id];\n            }\n            if (sc > bestScore || (sc == bestScore && cands[ci].totalWeight > bestTotal)) {\n                bestScore = sc;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n\n        selected[pos] = best;\n        usedCand[best] = 1;\n        for (int id : cands[best].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    vector<string> rows(20);\n    for (int i = 0; i < 20; ++i) rows[i] = cands[selected[i]].row;\n    return rows;\n}\n\n// ---------- exact graph for local search ----------\n\nvoid build_exact_graph() {\n    int U = (int)pats.size();\n    cellEdges.assign(N * N, {});\n    long long totalEdges = 0;\n    for (int sid = 0; sid < U; ++sid) totalEdges += 800LL * (int)pats[sid].size();\n    int reservePerCell = (int)(totalEdges / (N * N)) + 64;\n    for (int c = 0; c < N * N; ++c) cellEdges[c].reserve(reservePerCell);\n\n    int P = U * 800;\n    plSid.clear();\n    plLen.clear();\n    plMatch.clear();\n    plSid.reserve(P);\n    plLen.reserve(P);\n    plMatch.reserve(P);\n\n    for (int sid = 0; sid < U; ++sid) {\n        const auto& s = pch[sid];\n        int k = (int)s.size();\n\n        // horizontal placements\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n                int base = r * N;\n                for (int t = 0; t < k; ++t) {\n                    int cell = base + ((c + t) % N);\n                    cellEdges[cell].push_back({pid, s[t]});\n                }\n            }\n        }\n\n        // vertical placements\n        for (int c = 0; c < N; ++c) {\n            for (int r = 0; r < N; ++r) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n                for (int t = 0; t < k; ++t) {\n                    int cell = ((r + t) % N) * N + c;\n                    cellEdges[cell].push_back({pid, s[t]});\n                }\n            }\n        }\n    }\n}\n\nlong long init_state(const Matrix& mat, vector<int>& fullCnt) {\n    fill(plMatch.begin(), plMatch.end(), 0);\n    for (int cell = 0; cell < N * N; ++cell) {\n        unsigned char ch = mat[cell];\n        for (const auto& e : cellEdges[cell]) {\n            if (e.req == ch) ++plMatch[e.pid];\n        }\n    }\n\n    fullCnt.assign(pats.size(), 0);\n    for (int pid = 0, P = (int)plSid.size(); pid < P; ++pid) {\n        if (plMatch[pid] == plLen[pid]) ++fullCnt[plSid[pid]];\n    }\n\n    long long score = 0;\n    for (int sid = 0; sid < (int)pats.size(); ++sid) {\n        if (fullCnt[sid] > 0) score += wt[sid];\n    }\n    return score;\n}\n\n// ---------- matrix constructors ----------\n\nMatrix transpose_matrix(const Matrix& a) {\n    Matrix b{};\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            b[c * N + r] = a[r * N + c];\n        }\n    }\n    return b;\n}\n\nMatrix make_matrix_from_rows(const vector<string>& rows, bool randomizeOrderShift, bool doTranspose) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    if (randomizeOrderShift) shuffle(ord.begin(), ord.end(), rng);\n\n    Matrix mat{};\n    for (int r = 0; r < N; ++r) {\n        const string& s = rows[ord[r]];\n        int sh = randomizeOrderShift ? (int)(rng() % N) : 0;\n        for (int c = 0; c < N; ++c) {\n            mat[r * N + c] = (unsigned char)(s[(c + sh) % N] - 'A');\n        }\n    }\n    if (doTranspose) mat = transpose_matrix(mat);\n    return mat;\n}\n\n// ---------- soft voting refinement ----------\n\nstruct StartResult {\n    long long score;\n    Matrix mat;\n};\n\nStartResult soft_refine_start(Matrix mat, int phases, long long softDeadlineMs) {\n    vector<int> tmpFull;\n    StartResult best{init_state(mat, tmpFull), mat};\n\n    for (int phase = 0; phase < phases; ++phase) {\n        if (elapsed_ms() > softDeadlineMs) break;\n\n        long long votes[N * N][8];\n        memset(votes, 0, sizeof(votes));\n\n        int inertia = (phase == 0 ? 120 : 60);\n        for (int cell = 0; cell < N * N; ++cell) votes[cell][mat[cell]] += inertia;\n\n        unsigned char row2[N][2 * N];\n        unsigned char col2[N][2 * N];\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < 2 * N; ++c) row2[r][c] = mat[r * N + (c % N)];\n        }\n        for (int c = 0; c < N; ++c) {\n            for (int r = 0; r < 2 * N; ++r) col2[c][r] = mat[(r % N) * N + c];\n        }\n\n        for (int sid = 0; sid < (int)pats.size(); ++sid) {\n            const auto& s = pch[sid];\n            int k = (int)s.size();\n\n            unsigned char scs[800];\n            int idx = 0;\n            int bestSc = -1;\n\n            // horizontal codes: r*20 + c\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (row2[r][c + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n            // vertical codes: 400 + c*20 + r\n            for (int c = 0; c < N; ++c) {\n                for (int r = 0; r < N; ++r) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (col2[c][r + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n\n            int req;\n            int band;\n            long long base0, base1, base2;\n            if (phase == 0) {\n                req = max(3, (k + 1) / 2);\n                band = 0;\n                base0 = 64;\n                base1 = 0;\n                base2 = 0;\n            } else if (phase == 1) {\n                req = max(3, k / 2);\n                band = 1;\n                base0 = 48;\n                base1 = 10;\n                base2 = 0;\n            } else if (phase == 2) {\n                req = max(2, (k - 1) / 2);\n                band = 1;\n                base0 = 40;\n                base1 = 14;\n                base2 = 0;\n            } else {\n                req = 2;\n                band = 2;\n                base0 = 32;\n                base1 = 12;\n                base2 = 4;\n            }\n\n            if (bestSc < req) continue;\n\n            const int cap0 = 6, cap1 = 4, cap2 = 2;\n            int sel0[cap0], sel1[cap1], sel2[cap2];\n            int n0 = 0, n1 = 0, n2 = 0;\n            int seen0 = 0, seen1 = 0, seen2 = 0;\n\n            auto reservoir_add = [&](int* arr, int& n, int cap, int& seen, int code) {\n                ++seen;\n                if (n < cap) {\n                    arr[n++] = code;\n                } else {\n                    int r = (int)(rng() % seen);\n                    if (r < cap) arr[r] = code;\n                }\n            };\n\n            for (int code = 0; code < 800; ++code) {\n                int d = bestSc - (int)scs[code];\n                if (d == 0) reservoir_add(sel0, n0, cap0, seen0, code);\n                else if (d == 1 && band >= 1) reservoir_add(sel1, n1, cap1, seen1, code);\n                else if (d == 2 && band >= 2) reservoir_add(sel2, n2, cap2, seen2, code);\n            }\n\n            long long total0 = 1LL * wt[sid] * k * base0;\n            long long total1 = 1LL * wt[sid] * k * base1;\n            long long total2 = 1LL * wt[sid] * k * base2;\n\n            auto add_code = [&](int code, long long w) {\n                if (w <= 0) return;\n                if (code < 400) {\n                    int r = code / N;\n                    int c = code % N;\n                    int base = r * N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = base + ((c + t) % N);\n                        votes[cell][s[t]] += w;\n                    }\n                } else {\n                    int x = code - 400;\n                    int c = x / N;\n                    int r = x % N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = ((r + t) % N) * N + c;\n                        votes[cell][s[t]] += w;\n                    }\n                }\n            };\n\n            if (n0 > 0) {\n                long long w = total0 / n0;\n                for (int i = 0; i < n0; ++i) add_code(sel0[i], w);\n            }\n            if (n1 > 0) {\n                long long w = total1 / n1;\n                for (int i = 0; i < n1; ++i) add_code(sel1[i], w);\n            }\n            if (n2 > 0) {\n                long long w = total2 / n2;\n                for (int i = 0; i < n2; ++i) add_code(sel2[i], w);\n            }\n        }\n\n        int changes = 0;\n        for (int cell = 0; cell < N * N; ++cell) {\n            unsigned char old = mat[cell];\n            unsigned char bestCh = old;\n            long long bestV = votes[cell][old];\n            for (unsigned char ch = 0; ch < 8; ++ch) {\n                if (votes[cell][ch] > bestV) {\n                    bestV = votes[cell][ch];\n                    bestCh = ch;\n                }\n            }\n            if (bestCh != old) {\n                mat[cell] = bestCh;\n                ++changes;\n            }\n        }\n\n        long long sc = init_state(mat, tmpFull);\n        if (sc > best.score) best = {sc, mat};\n        if (changes == 0) break;\n    }\n\n    return best;\n}\n\n// ---------- exact hill-climb ----------\n\nStartResult exact_hillclimb(Matrix mat, int maxPass, long long endMs) {\n    vector<int> fullCnt;\n    long long curScore = init_state(mat, fullCnt);\n    StartResult best{curScore, mat};\n\n    vector<int> order(N * N);\n    iota(order.begin(), order.end(), 0);\n\n    int U = (int)pats.size();\n    vector<int> seen(U, 0), inc(U, 0), dec(U, 0), touched;\n    touched.reserve(U);\n    int stamp = 1;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        if (elapsed_ms() > endMs) break;\n        shuffle(order.begin(), order.end(), rng);\n        bool improved = false;\n\n        for (int cell : order) {\n            if (elapsed_ms() > endMs) break;\n\n            unsigned char old = mat[cell];\n            long long bestDelta = 0;\n            unsigned char bestCh = old;\n\n            for (unsigned char nw = 0; nw < 8; ++nw) {\n                if (nw == old) continue;\n                ++stamp;\n                touched.clear();\n\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == nw);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n\n                    if (seen[sid] != stamp) {\n                        seen[sid] = stamp;\n                        inc[sid] = 0;\n                        dec[sid] = 0;\n                        touched.push_back(sid);\n                    }\n\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) ++dec[sid];\n                    } else {\n                        if ((int)plMatch[pid] + 1 == (int)plLen[pid]) ++inc[sid];\n                    }\n                }\n\n                long long delta = 0;\n                for (int sid : touched) {\n                    int oldCnt = fullCnt[sid];\n                    int newCnt = oldCnt - dec[sid] + inc[sid];\n                    if (oldCnt == 0 && newCnt > 0) delta += wt[sid];\n                    else if (oldCnt > 0 && newCnt == 0) delta -= wt[sid];\n                }\n\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestCh = nw;\n                }\n            }\n\n            if (bestCh != old) {\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == bestCh);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) --fullCnt[sid];\n                        --plMatch[pid];\n                    } else {\n                        ++plMatch[pid];\n                        if (plMatch[pid] == plLen[pid]) ++fullCnt[sid];\n                    }\n                }\n                mat[cell] = bestCh;\n                curScore += bestDelta;\n                improved = true;\n\n                if (curScore > best.score) best = {curScore, mat};\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gStart = chrono::steady_clock::now();\n\n    int Nin, M;\n    cin >> Nin >> M;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M * 2);\n\n    vector<int> charFreq(8, 0);\n\n    for (int i = 0; i < M; ++i) {\n        string s;\n        cin >> s;\n        auto it = mp.find(s);\n        if (it == mp.end()) {\n            int id = (int)pats.size();\n            mp.emplace(s, id);\n            pats.push_back(s);\n            wt.push_back(1);\n        } else {\n            wt[it->second]++;\n        }\n        for (char c : s) ++charFreq[c - 'A'];\n    }\n\n    int U = (int)pats.size();\n    pch.resize(U);\n    for (int i = 0; i < U; ++i) {\n        pch[i].resize(pats[i].size());\n        for (int j = 0; j < (int)pats[i].size(); ++j) pch[i][j] = (unsigned char)(pats[i][j] - 'A');\n    }\n\n    vector<long long> imp(U);\n    for (int i = 0; i < U; ++i) {\n        int L = (int)pats[i].size();\n        imp[i] = 1LL * wt[i] * L * L;\n    }\n    impOrder.resize(U);\n    iota(impOrder.begin(), impOrder.end(), 0);\n    sort(impOrder.begin(), impOrder.end(), [&](int a, int b) {\n        if (imp[a] != imp[b]) return imp[a] > imp[b];\n        return pats[a].size() > pats[b].size();\n    });\n\n    // Stage 1: row-based assembly\n    vector<string> rows = build_initial_rows(charFreq);\n\n    // Stage 2: build exact placement graph once\n    build_exact_graph();\n\n    // Stage 3: multi-start refinement\n    vector<Matrix> starts;\n    starts.push_back(make_matrix_from_rows(rows, false, false));\n    starts.push_back(make_matrix_from_rows(rows, false, true));\n    starts.push_back(make_matrix_from_rows(rows, true, false));\n    starts.push_back(make_matrix_from_rows(rows, true, true));\n    starts.push_back(make_matrix_from_rows(rows, true, false));\n\n    vector<StartResult> refined;\n    refined.reserve(starts.size());\n\n    long long softDeadline = 2350;\n    for (int si = 0; si < (int)starts.size(); ++si) {\n        if (elapsed_ms() > softDeadline) break;\n        int phases = (elapsed_ms() < 1400 ? 4 : 3);\n        StartResult res = soft_refine_start(starts[si], phases, softDeadline);\n        refined.push_back(res);\n    }\n\n    if (refined.empty()) {\n        vector<int> tmp;\n        refined.push_back({init_state(starts[0], tmp), starts[0]});\n    }\n\n    sort(refined.begin(), refined.end(), [&](const StartResult& a, const StartResult& b) {\n        return a.score > b.score;\n    });\n\n    StartResult globalBest = refined[0];\n\n    // exact hill-climb on best 1-2 starts\n    for (int i = 0; i < min<int>(2, refined.size()); ++i) {\n        if (elapsed_ms() > 2920) break;\n        int maxPass = (i == 0 ? 2 : 1);\n        StartResult res = exact_hillclimb(refined[i].mat, maxPass, 2920);\n        if (res.score > globalBest.score) globalBest = res;\n    }\n\n    // Output\n    for (int r = 0; r < N; ++r) {\n        string out(N, 'A');\n        for (int c = 0; c < N; ++c) out[c] = char('A' + globalBest.mat[r * N + c]);\n        cout << out << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\n\nstatic constexpr int INF_INT = 1e9;\nstatic constexpr ll INF_LL = (ll)4e15;\n\nstruct Task {\n    // type: 0=fixed cell, 1=horizontal segment, 2=vertical segment\n    int type;\n    int seg;\n    int cell;\n};\n\nstruct CandidateResult {\n    bool valid = false;\n    ll cost = (1LL << 60);\n    string path;\n};\n\nint N, si, sj;\nvector<string> gridc;\nvector<vector<int>> idg;\n\nint Rcnt;\nint sId;\nvector<int> rr, cc, cellW;\nvector<vector<int>> nbrs;\n\nint Hcnt, Vcnt;\nvector<int> hid, vid;\nvector<vector<int>> cellsH, cellsV;\nvector<vector<pair<int,int>>> adjHFull, adjHRes; // (v, cell)\n\nint sH, sV;\nvector<char> activeH, activeV;\nvector<int> bestCellH, bestCellV;\nvector<int> distStart;\n\nchrono::steady_clock::time_point globalStart;\n\nll elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - globalStart\n    ).count();\n}\n\nchar dirChar(int a, int b) {\n    if (rr[b] == rr[a] - 1 && cc[b] == cc[a]) return 'U';\n    if (rr[b] == rr[a] + 1 && cc[b] == cc[a]) return 'D';\n    if (rr[b] == rr[a] && cc[b] == cc[a] - 1) return 'L';\n    if (rr[b] == rr[a] && cc[b] == cc[a] + 1) return 'R';\n    return '?';\n}\n\nvoid runDijkstra(int src, vector<int>& dist, vector<int>& parent) {\n    dist.assign(Rcnt, INF_INT);\n    parent.assign(Rcnt, -1);\n    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [d, u] = pq.top();\n        pq.pop();\n        if (d != dist[u]) continue;\n        for (int v : nbrs[u]) {\n            int nd = d + cellW[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                parent[v] = u;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\nvoid hopcroftKarp(\n    const vector<char>& selH,\n    const vector<char>& selV,\n    const vector<vector<pair<int,int>>>& adj,\n    vector<int>& matchH,\n    vector<int>& matchV\n) {\n    matchH.assign(Hcnt, -1);\n    matchV.assign(Vcnt, -1);\n    vector<int> level(Hcnt, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(level.begin(), level.end(), -1);\n        bool found = false;\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) {\n                level[h] = 0;\n                q.push(h);\n            }\n        }\n        while (!q.empty()) {\n            int h = q.front(); q.pop();\n            for (auto [v, cid] : adj[h]) {\n                (void)cid;\n                if (!selV[v]) continue;\n                int h2 = matchV[v];\n                if (h2 == -1) {\n                    found = true;\n                } else if (level[h2] == -1) {\n                    level[h2] = level[h] + 1;\n                    q.push(h2);\n                }\n            }\n        }\n        return found;\n    };\n\n    function<bool(int)> dfs = [&](int h) -> bool {\n        for (auto [v, cid] : adj[h]) {\n            (void)cid;\n            if (!selV[v]) continue;\n            int h2 = matchV[v];\n            if (h2 == -1 || (level[h2] == level[h] + 1 && dfs(h2))) {\n                matchH[h] = v;\n                matchV[v] = h;\n                return true;\n            }\n        }\n        level[h] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) dfs(h);\n        }\n    }\n}\n\npair<vector<char>, vector<char>> buildCanonicalMVC() {\n    vector<char> selH = activeH, selV = activeV;\n    vector<int> matchH, matchV;\n    hopcroftKarp(selH, selV, adjHRes, matchH, matchV);\n\n    vector<char> visH(Hcnt, false), visV(Vcnt, false);\n    queue<int> q;\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h] && matchH[h] == -1) {\n            visH[h] = true;\n            q.push(h);\n        }\n    }\n\n    while (!q.empty()) {\n        int h = q.front(); q.pop();\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (matchH[h] == v) continue; // use only non-matching edges H->V\n            if (!visV[v]) {\n                visV[v] = true;\n                int h2 = matchV[v];\n                if (h2 != -1 && !visH[h2]) {\n                    visH[h2] = true;\n                    q.push(h2);\n                }\n            }\n        }\n    }\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !visH[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && visV[v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\npair<vector<char>, vector<char>> buildWeightedVC(\n    const vector<ll>& wH,\n    const vector<ll>& wV\n) {\n    int S = Hcnt + Vcnt;\n    int T = S + 1;\n    mf_graph<ll> mf(T + 1);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) mf.add_edge(S, h, wH[h]);\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) mf.add_edge(Hcnt + v, T, wV[v]);\n    }\n    for (int h = 0; h < Hcnt; h++) {\n        if (!activeH[h]) continue;\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (!activeV[v]) continue;\n            mf.add_edge(h, Hcnt + v, INF_LL);\n        }\n    }\n\n    mf.flow(S, T);\n    auto reach = mf.min_cut(S);\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h] && !reach[h]) ansH[h] = true;\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v] && reach[Hcnt + v]) ansV[v] = true;\n    }\n    return {ansH, ansV};\n}\n\nvector<Task> buildTasksFromSelected(const vector<char>& selH, const vector<char>& selV) {\n    vector<int> matchH, matchV;\n    hopcroftKarp(selH, selV, adjHFull, matchH, matchV);\n\n    vector<Task> tasks;\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (!selH[h]) continue;\n        if (matchH[h] != -1) {\n            int v = matchH[h];\n            int cid = -1;\n            for (auto [vv, ccid] : adjHFull[h]) {\n                if (vv == v) {\n                    cid = ccid;\n                    break;\n                }\n            }\n            if (cid != -1) tasks.push_back({0, -1, cid});\n        }\n    }\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (selH[h] && matchH[h] == -1) {\n            tasks.push_back({1, h, bestCellH[h]});\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (selV[v] && matchV[v] == -1) {\n            tasks.push_back({2, v, bestCellV[v]});\n        }\n    }\n    return tasks;\n}\n\nvector<int> routeNearestNeighbor(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    vector<int> route;\n    route.reserve(M + 2);\n    route.push_back(0);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    int cur = 0;\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        ll bestD = (1LL << 60);\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeCheapestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    used[0] = true;\n\n    int first = 1;\n    ll bestFirst = (1LL << 60);\n    for (int p = 1; p <= M; p++) {\n        ll val = d0[0][p] + d0[p][0];\n        if (val < bestFirst) {\n            bestFirst = val;\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        ll bestInc = (1LL << 60);\n        int bestP = -1, bestPos = -1;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n                int a = route[pos], b = route[pos + 1];\n                ll inc = d0[a][p] + d0[p][b] - d0[a][b];\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestP = p;\n                    bestPos = pos;\n                }\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, bestP);\n        used[bestP] = true;\n    }\n    return route;\n}\n\nll routeCostMat(const vector<int>& route, const vector<vector<ll>>& mat) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) s += mat[route[i]][route[i + 1]];\n    return s;\n}\n\nvoid improve2opt(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    if (L <= 4) return;\n\n    for (int pass = 0; pass < 4; pass++) {\n        bool improved = false;\n        for (int i = 1; i + 1 < L; i++) {\n            for (int j = i + 1; j + 1 < L; j++) {\n                ll oldv = d0[route[i - 1]][route[i]] + d0[route[j]][route[j + 1]];\n                ll newv = d0[route[i - 1]][route[j]] + d0[route[i]][route[j + 1]];\n                if (newv < oldv) {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nstring reconstructPath(\n    const vector<int>& route,\n    const vector<int>& sourceCells,\n    const vector<vector<int>>& parentAll\n) {\n    string out;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        int aidx = route[i];\n        int bidx = route[i + 1];\n        if (aidx == bidx) continue;\n        int src = sourceCells[aidx];\n        int dst = sourceCells[bidx];\n        vector<int> rev;\n        int cur = dst;\n        while (cur != src) {\n            rev.push_back(cur);\n            cur = parentAll[aidx][cur];\n            if (cur == -1) return \"\";\n        }\n        reverse(rev.begin(), rev.end());\n        int prev = src;\n        for (int x : rev) {\n            char c = dirChar(prev, x);\n            if (c == '?') return \"\";\n            out.push_back(c);\n            prev = x;\n        }\n    }\n    return out;\n}\n\npair<bool,ll> validateAndCost(const string& path) {\n    vector<char> covH(Hcnt, false), covV(Vcnt, false);\n    int cur = sId;\n    covH[hid[cur]] = true;\n    covV[vid[cur]] = true;\n    ll cost = 0;\n\n    for (char ch : path) {\n        int ni = rr[cur], nj = cc[cur];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return {false, 0};\n\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return {false, 0};\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return {false, 0};\n\n        cost += cellW[nxt];\n        cur = nxt;\n        covH[hid[cur]] = true;\n        covV[vid[cur]] = true;\n    }\n\n    if (cur != sId) return {false, 0};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        if (!covH[hid[cid]] && !covV[vid[cid]]) return {false, 0};\n    }\n    return {true, cost};\n}\n\nCandidateResult solveCandidate(vector<Task> tasks) {\n    CandidateResult res;\n    if (tasks.size() > 800) return res;\n    if (elapsed_ms() > 2700) return res;\n\n    if (tasks.empty()) {\n        auto [ok, c] = validateAndCost(\"\");\n        if (ok) {\n            res.valid = true;\n            res.cost = c;\n            res.path = \"\";\n        }\n        return res;\n    }\n\n    vector<int> sourceCells;\n    vector<int> sourceW;\n    vector<vector<int>> distAll, parentAll;\n    vector<vector<ll>> d0, dir0;\n    vector<int> bestRoute;\n\n    auto buildData = [&](const vector<Task>& curTasks) -> bool {\n        int M = (int)curTasks.size() + 1;\n        sourceCells.assign(M, -1);\n        sourceW.assign(M, 0);\n        sourceCells[0] = sId;\n        for (int i = 0; i < (int)curTasks.size(); i++) sourceCells[i + 1] = curTasks[i].cell;\n        for (int i = 0; i < M; i++) sourceW[i] = cellW[sourceCells[i]];\n\n        distAll.assign(M, vector<int>());\n        parentAll.assign(M, vector<int>());\n        for (int i = 0; i < M; i++) {\n            if ((i & 15) == 0 && elapsed_ms() > 2850) return false;\n            runDijkstra(sourceCells[i], distAll[i], parentAll[i]);\n        }\n\n        d0.assign(M, vector<ll>(M, 0));\n        dir0.assign(M, vector<ll>(M, 0));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) {\n                    d0[i][j] = 0;\n                    dir0[i][j] = 0;\n                } else {\n                    dir0[i][j] = distAll[i][sourceCells[j]];\n                    d0[i][j] = dir0[i][j] + sourceW[i];\n                }\n            }\n        }\n        return true;\n    };\n\n    for (int iter = 0; iter < 2; iter++) {\n        if (!buildData(tasks)) return res;\n\n        auto r1 = routeCheapestInsertion(d0);\n        auto r2 = routeNearestNeighbor(d0);\n        improve2opt(r1, d0);\n        improve2opt(r2, d0);\n\n        bestRoute = (routeCostMat(r1, d0) <= routeCostMat(r2, d0) ? r1 : r2);\n\n        if (iter == 0) {\n            int M = (int)tasks.size();\n            vector<int> pos(M + 1, -1);\n            for (int i = 0; i < (int)bestRoute.size(); i++) pos[bestRoute[i]] = i;\n\n            bool changed = false;\n            vector<int> newCells(M);\n            for (int i = 0; i < M; i++) newCells[i] = tasks[i].cell;\n\n            for (int ti = 0; ti < M; ti++) {\n                if (tasks[ti].type == 0) continue;\n\n                int idx = ti + 1;\n                int p = pos[idx];\n                if (p <= 0 || p + 1 >= (int)bestRoute.size()) continue;\n                int prevIdx = bestRoute[p - 1];\n                int nextIdx = bestRoute[p + 1];\n\n                const vector<int>& candCells =\n                    (tasks[ti].type == 1 ? cellsH[tasks[ti].seg] : cellsV[tasks[ti].seg]);\n\n                ll bestVal = (1LL << 60);\n                int bestCid = tasks[ti].cell;\n                for (int cid : candCells) {\n                    ll val = 0;\n                    val += distAll[prevIdx][cid];\n                    val += distAll[nextIdx][cid] + sourceW[nextIdx] - cellW[cid];\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestCid = cid;\n                    }\n                }\n                if (bestCid != tasks[ti].cell) {\n                    newCells[ti] = bestCid;\n                    changed = true;\n                }\n            }\n\n            if (changed) {\n                for (int i = 0; i < M; i++) tasks[i].cell = newCells[i];\n                continue;\n            }\n        }\n        break;\n    }\n\n    string path = reconstructPath(bestRoute, sourceCells, parentAll);\n    if (path.empty()) {\n        // empty is okay only if it really covers everything\n        auto [ok, c] = validateAndCost(path);\n        if (ok) {\n            res.valid = true;\n            res.cost = c;\n            res.path = path;\n        }\n        return res;\n    }\n\n    auto [ok, c] = validateAndCost(path);\n    if (ok) {\n        res.valid = true;\n        res.cost = c;\n        res.path = move(path);\n    }\n    return res;\n}\n\nstring buildFallbackDFSRoute() {\n    vector<char> vis(Rcnt, false);\n    string out;\n\n    vector<int> it(Rcnt, 0);\n    vector<int> st;\n    st.push_back(sId);\n    vis[sId] = true;\n\n    while (!st.empty()) {\n        int u = st.back();\n        if (it[u] == (int)nbrs[u].size()) {\n            st.pop_back();\n            if (!st.empty()) {\n                int p = st.back();\n                out.push_back(dirChar(u, p));\n            }\n            continue;\n        }\n        int v = nbrs[u][it[u]++];\n        if (vis[v]) continue;\n        vis[v] = true;\n        out.push_back(dirChar(u, v));\n        st.push_back(v);\n    }\n    return out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    globalStart = chrono::steady_clock::now();\n\n    cin >> N >> si >> sj;\n    gridc.resize(N);\n    for (int i = 0; i < N; i++) cin >> gridc[i];\n\n    idg.assign(N, vector<int>(N, -1));\n    rr.clear(); cc.clear(); cellW.clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (gridc[i][j] != '#') {\n                idg[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                cellW.push_back(gridc[i][j] - '0');\n            }\n        }\n    }\n    Rcnt = (int)rr.size();\n    sId = idg[si][sj];\n\n    nbrs.assign(Rcnt, {});\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int i = rr[cid], j = cc[cid];\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) {\n                int nid = idg[ni][nj];\n                if (nid != -1) nbrs[cid].push_back(nid);\n            }\n        }\n    }\n    for (int u = 0; u < Rcnt; u++) {\n        sort(nbrs[u].begin(), nbrs[u].end(), [&](int a, int b) {\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    hid.assign(Rcnt, -1);\n    vid.assign(Rcnt, -1);\n\n    Hcnt = 0;\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (idg[i][j] == -1) {\n                j++;\n                continue;\n            }\n            int h = Hcnt++;\n            cellsH.push_back({});\n            while (j < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                hid[cid] = h;\n                cellsH[h].push_back(cid);\n                j++;\n            }\n        }\n    }\n\n    Vcnt = 0;\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (idg[i][j] == -1) {\n                i++;\n                continue;\n            }\n            int v = Vcnt++;\n            cellsV.push_back({});\n            while (i < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                vid[cid] = v;\n                cellsV[v].push_back(cid);\n                i++;\n            }\n        }\n    }\n\n    adjHFull.assign(Hcnt, {});\n    for (int cid = 0; cid < Rcnt; cid++) {\n        adjHFull[hid[cid]].push_back({vid[cid], cid});\n    }\n\n    vector<int> dummyParent;\n    runDijkstra(sId, distStart, dummyParent);\n\n    bestCellH.assign(Hcnt, -1);\n    bestCellV.assign(Vcnt, -1);\n\n    auto betterCell = [&](int a, int b) {\n        if (a == -1) return true;\n        if (distStart[b] != distStart[a]) return distStart[b] < distStart[a];\n        if (cellW[b] != cellW[a]) return cellW[b] < cellW[a];\n        if (rr[b] != rr[a]) return rr[b] < rr[a];\n        return cc[b] < cc[a];\n    };\n\n    for (int h = 0; h < Hcnt; h++) {\n        for (int cid : cellsH[h]) {\n            if (bestCellH[h] == -1 || betterCell(bestCellH[h], cid)) {\n                bestCellH[h] = cid;\n            }\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        for (int cid : cellsV[v]) {\n            if (bestCellV[v] == -1 || betterCell(bestCellV[v], cid)) {\n                bestCellV[v] = cid;\n            }\n        }\n    }\n\n    for (int h = 0; h < Hcnt; h++) {\n        sort(adjHFull[h].begin(), adjHFull[h].end(), [&](auto A, auto B) {\n            int a = A.second, b = B.second;\n            if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    sH = hid[sId];\n    sV = vid[sId];\n\n    activeH.assign(Hcnt, false);\n    activeV.assign(Vcnt, false);\n    adjHRes.assign(Hcnt, {});\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int h = hid[cid], v = vid[cid];\n        if (h == sH || v == sV) continue; // already visible from start\n        activeH[h] = true;\n        activeV[v] = true;\n        adjHRes[h].push_back({v, cid});\n    }\n\n    vector<ll> segCostH(Hcnt, 0), segCostV(Vcnt, 0);\n    for (int h = 0; h < Hcnt; h++) segCostH[h] = distStart[bestCellH[h]];\n    for (int v = 0; v < Vcnt; v++) segCostV[v] = distStart[bestCellV[v]];\n\n    string bestPath = buildFallbackDFSRoute();\n    auto [fbok, fbcost] = validateAndCost(bestPath);\n    if (!fbok) {\n        bestPath = \"\";\n        fbcost = (1LL << 60);\n    }\n    ll bestCost = fbcost;\n\n    vector<pair<vector<char>, vector<char>>> candSets;\n\n    candSets.push_back(buildCanonicalMVC());\n\n    ll sumSeg = 0;\n    for (int h = 0; h < Hcnt; h++) if (activeH[h]) sumSeg += segCostH[h];\n    for (int v = 0; v < Vcnt; v++) if (activeV[v]) sumSeg += segCostV[v];\n    ll base = sumSeg + 1;\n\n    vector<ll> wH1(Hcnt, 0), wV1(Vcnt, 0);\n    vector<ll> wH2(Hcnt, 0), wV2(Vcnt, 0);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) {\n            wH1[h] = base + segCostH[h];\n            wH2[h] = 1 + segCostH[h];\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) {\n            wV1[v] = base + segCostV[v];\n            wV2[v] = 1 + segCostV[v];\n        }\n    }\n\n    candSets.push_back(buildWeightedVC(wH1, wV1));\n    candSets.push_back(buildWeightedVC(wH2, wV2));\n\n    vector<char> allH = activeH, allV = activeV;\n    candSets.push_back({allH, vector<char>(Vcnt, false)});\n    candSets.push_back({vector<char>(Hcnt, false), allV});\n\n    for (auto& [selH, selV] : candSets) {\n        if (elapsed_ms() > 2750) break;\n        vector<Task> tasks = buildTasksFromSelected(selH, selV);\n        CandidateResult cr = solveCandidate(tasks);\n        if (cr.valid && cr.cost < bestCost) {\n            bestCost = cr.cost;\n            bestPath = move(cr.path);\n        }\n    }\n\n    if (bestPath.empty()) {\n        // avoid zero-length tour if possible\n        if (!nbrs[sId].empty()) {\n            int v = nbrs[sId][0];\n            string tmp;\n            tmp.push_back(dirChar(sId, v));\n            tmp.push_back(dirChar(v, sId));\n            auto [ok, c] = validateAndCost(tmp);\n            if (ok) bestPath = tmp;\n        }\n    }\n\n    cout << bestPath << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int MAXN = 1000;\nstatic constexpr ll INF64 = (1LL << 62);\nstatic constexpr ll DUMMY_UTILITY = -4'000'000'000'000LL;\n\nstruct Observation {\n    int task;\n    int dur;\n};\n\nstruct Member {\n    int current_task = -1;\n    int start_day = -1;\n    vector<Observation> obs;\n    vector<int> est;\n    bool busy() const { return current_task != -1; }\n};\n\nstruct Solver {\n    int N, M, K, R;\n    vector<vector<int>> req;\n    vector<vector<int>> g;\n    vector<int> indeg_rem;\n    vector<int> state; // 0:not started, 1:in progress, 2:done\n    vector<Member> members;\n\n    vector<int> maxD;\n    vector<double> prior_cap;\n    vector<int> prior_int;\n    vector<double> rank_skill;\n    vector<double> easy_skill;\n\n    vector<int> desc_count;\n    vector<double> avg_proc;\n    vector<double> up_rank;\n    vector<double> base_priority_static;\n    vector<double> global_easy_dur;\n\n    int completed_tasks = 0;\n\n    static double expected_duration_from_w(double w) {\n        if (w <= 0.0) return 1.0;\n        static const double E[5] = {\n            1.0,\n            13.0 / 7.0,\n            17.0 / 7.0,\n            22.0 / 7.0,\n            4.0\n        };\n        if (w < 4.0) {\n            int a = (int)floor(w);\n            double f = w - a;\n            return E[a] * (1.0 - f) + E[a + 1] * f;\n        }\n        return w;\n    }\n\n    double predict_duration_with_skill(const vector<double>& skill, int task) const {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double diff = (double)req[task][k] - skill[k];\n            if (diff > 0) w += diff;\n        }\n        return expected_duration_from_w(w);\n    }\n\n    static pair<int,int> duration_interval(int t) {\n        if (t <= 1) return {0, 4};\n        return {max(1, t - 3), t + 3};\n    }\n\n    void read_input() {\n        cin >> N >> M >> K >> R;\n        req.assign(N, vector<int>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) cin >> req[i][k];\n        }\n        g.assign(N, {});\n        indeg_rem.assign(N, 0);\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            g[u].push_back(v);\n            indeg_rem[v]++;\n        }\n        state.assign(N, 0);\n        members.assign(M, Member{});\n    }\n\n    void preprocess() {\n        maxD.assign(K, 0);\n        vector<double> meanD(K, 0.0);\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                maxD[k] = max(maxD[k], req[i][k]);\n                meanD[k] += req[i][k];\n            }\n        }\n        for (int k = 0; k < K; k++) meanD[k] /= N;\n\n        prior_cap.assign(K, 0.0);\n        prior_int.assign(K, 0);\n        rank_skill.assign(K, 0.0);\n        easy_skill.assign(K, 0.0);\n\n        for (int k = 0; k < K; k++) {\n            double p = 1.6 * meanD[k];\n            p = min<double>(p, maxD[k]);\n            if (p < 0) p = 0;\n            prior_cap[k] = p;\n            prior_int[k] = (int)llround(p);\n            prior_int[k] = max(0, min(prior_int[k], maxD[k]));\n            rank_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.75);\n            easy_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.80);\n        }\n\n        for (int j = 0; j < M; j++) {\n            members[j].est = prior_int;\n        }\n\n        // Exact descendant counts with bitset.\n        vector<bitset<MAXN>> reach(N);\n        desc_count.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            bitset<MAXN> bs;\n            for (int to : g[i]) {\n                bs |= reach[to];\n                bs.set(to);\n            }\n            reach[i] = bs;\n            desc_count[i] = (int)bs.count();\n        }\n\n        avg_proc.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            avg_proc[i] = predict_duration_with_skill(rank_skill, i);\n        }\n\n        up_rank.assign(N, 0.0);\n        for (int i = N - 1; i >= 0; i--) {\n            double mx = 0.0;\n            for (int to : g[i]) mx = max(mx, up_rank[to]);\n            up_rank[i] = avg_proc[i] + mx;\n        }\n\n        base_priority_static.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            base_priority_static[i] = up_rank[i] + 0.03 * desc_count[i];\n        }\n\n        global_easy_dur.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            global_easy_dur[i] = predict_duration_with_skill(easy_skill, i);\n        }\n    }\n\n    void reestimate_member(int j) {\n        auto& mem = members[j];\n        int nobs = (int)mem.obs.size();\n        if (nobs == 0) {\n            mem.est = prior_int;\n            return;\n        }\n        if ((int)mem.est.size() != K) mem.est = prior_int;\n\n        vector<int> s = mem.est;\n        for (int k = 0; k < K; k++) {\n            s[k] = max(0, min(s[k], maxD[k]));\n        }\n\n        vector<int> task_id(nobs), L(nobs), U(nobs);\n        for (int i = 0; i < nobs; i++) {\n            task_id[i] = mem.obs[i].task;\n            auto [l, u] = duration_interval(mem.obs[i].dur);\n            L[i] = l;\n            U[i] = u;\n        }\n\n        vector<int> pred(nobs, 0);\n        for (int i = 0; i < nobs; i++) {\n            int t = task_id[i];\n            int w = 0;\n            for (int k = 0; k < K; k++) {\n                w += max(0, req[t][k] - s[k]);\n            }\n            pred[i] = w;\n        }\n\n        int passes = (nobs < 8 ? 3 : 2);\n        double reg = 10.0 / (nobs + 3.0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            for (int k = 0; k < K; k++) {\n                int old = s[k];\n                int lim = maxD[k];\n\n                vector<int> dk(nobs), oldPart(nobs);\n                for (int i = 0; i < nobs; i++) {\n                    int dkk = req[task_id[i]][k];\n                    dk[i] = dkk;\n                    oldPart[i] = max(0, dkk - old);\n                }\n\n                double bestObj = 1e100;\n                int bestX = old;\n\n                for (int x = 0; x <= lim; x++) {\n                    double obj = reg * (x - prior_int[k]) * (x - prior_int[k]);\n                    for (int i = 0; i < nobs; i++) {\n                        int w = pred[i] - oldPart[i] + max(0, dk[i] - x);\n                        if (w < L[i]) {\n                            double d = (double)(L[i] - w);\n                            obj += d * d;\n                        } else if (w > U[i]) {\n                            double d = (double)(w - U[i]);\n                            obj += d * d;\n                        }\n                    }\n                    if (obj < bestObj) {\n                        bestObj = obj;\n                        bestX = x;\n                    }\n                }\n\n                if (bestX != old) {\n                    for (int i = 0; i < nobs; i++) {\n                        pred[i] = pred[i] - oldPart[i] + max(0, dk[i] - bestX);\n                    }\n                    s[k] = bestX;\n                }\n            }\n        }\n\n        mem.est = s;\n    }\n\n    vector<int> hungarian_min(const vector<vector<ll>>& cost) {\n        int n = (int)cost.size();\n        int m = (int)cost[0].size();\n        // Requires n <= m\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF64);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF64;\n                for (int j = 1; j <= m; j++) {\n                    if (used[j]) continue;\n                    ll cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0 != 0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    vector<pair<int,int>> choose_assignments(int day) {\n        vector<int> free_members, ready_tasks;\n        for (int j = 0; j < M; j++) if (!members[j].busy()) free_members.push_back(j);\n        for (int i = 0; i < N; i++) if (state[i] == 0 && indeg_rem[i] == 0) ready_tasks.push_back(i);\n\n        if (free_members.empty() || ready_tasks.empty()) return {};\n\n        vector<vector<double>> eff_skill(M, vector<double>(K, 0.0));\n        for (int j = 0; j < M; j++) {\n            double conf = (double)members[j].obs.size() / (members[j].obs.size() + 5.0);\n            for (int k = 0; k < K; k++) {\n                eff_skill[j][k] = conf * members[j].est[k] + (1.0 - conf) * prior_cap[k];\n            }\n        }\n\n        vector<double> dynP(N, -1e100);\n        vector<pair<double,int>> order;\n        order.reserve(ready_tasks.size());\n\n        for (int task : ready_tasks) {\n            double unlock_bonus = 0.0;\n            for (int to : g[task]) {\n                if (state[to] == 0 && indeg_rem[to] == 1) {\n                    unlock_bonus += base_priority_static[to];\n                }\n            }\n            double p = base_priority_static[task] + 0.15 * unlock_bonus - 1e-4 * task;\n            dynP[task] = p;\n            order.push_back({p, task});\n        }\n\n        sort(order.begin(), order.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        auto raw_pred = [&](int member, int task) -> double {\n            return predict_duration_with_skill(eff_skill[member], task);\n        };\n\n        vector<char> used_member(M, false), used_task(N, false);\n        vector<pair<int,int>> res;\n\n        int urgent = 0;\n        if ((int)free_members.size() >= 2) {\n            urgent = min<int>((int)free_members.size(), (completed_tasks < 2 * M ? 2 : 3));\n        }\n\n        int ptr = 0;\n        while (urgent > 0 && ptr < (int)order.size()) {\n            int task = order[ptr++].second;\n            if (used_task[task]) continue;\n\n            double bestDur = 1e100;\n            int bestMember = -1;\n            for (int j : free_members) {\n                if (used_member[j]) continue;\n                double d = raw_pred(j, task);\n                if (d < bestDur - 1e-12 || (abs(d - bestDur) <= 1e-12 && j < bestMember)) {\n                    bestDur = d;\n                    bestMember = j;\n                }\n            }\n            if (bestMember == -1) break;\n\n            used_member[bestMember] = true;\n            used_task[task] = true;\n            res.push_back({bestMember, task});\n            urgent--;\n        }\n\n        vector<int> rem_members;\n        for (int j : free_members) if (!used_member[j]) rem_members.push_back(j);\n\n        vector<int> rem_tasks_order;\n        for (auto [p, t] : order) if (!used_task[t]) rem_tasks_order.push_back(t);\n\n        if (rem_members.empty() || rem_tasks_order.empty()) return res;\n\n        vector<int> cand;\n        vector<char> chosen(N, false);\n\n        if ((int)rem_tasks_order.size() <= 80) {\n            cand = rem_tasks_order;\n            for (int t : cand) chosen[t] = true;\n        } else {\n            const int TOP_PRIO = 50;\n            const int TOP_EASY = 25;\n\n            for (int i = 0; i < (int)rem_tasks_order.size() && (int)cand.size() < TOP_PRIO; i++) {\n                int t = rem_tasks_order[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            vector<int> easy = rem_tasks_order;\n            sort(easy.begin(), easy.end(), [&](int a, int b) {\n                if (global_easy_dur[a] != global_easy_dur[b]) return global_easy_dur[a] < global_easy_dur[b];\n                if (dynP[a] != dynP[b]) return dynP[a] > dynP[b];\n                return a < b;\n            });\n\n            for (int i = 0; i < (int)easy.size() && i < TOP_EASY; i++) {\n                int t = easy[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            int need = min<int>((int)rem_tasks_order.size(), max<int>((int)rem_members.size(), 20));\n            for (int t : rem_tasks_order) {\n                if ((int)cand.size() >= need) break;\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n        }\n\n        if (cand.empty()) return res;\n\n        int n = (int)rem_members.size();\n        int m = (int)cand.size() + n; // add dummy columns\n        vector<vector<ll>> util(n, vector<ll>(m, DUMMY_UTILITY));\n\n        for (int r = 0; r < n; r++) {\n            int member = rem_members[r];\n            int oc = (int)members[member].obs.size();\n            for (int c = 0; c < (int)cand.size(); c++) {\n                int task = cand[c];\n                double dur = raw_pred(member, task);\n\n                if (oc == 0) {\n                    if (completed_tasks < M) dur *= 2.2;\n                    else if (completed_tasks < 3 * M) dur *= 1.6;\n                } else if (oc == 1 && completed_tasks < 3 * M) {\n                    dur *= 1.2;\n                }\n\n                double u = dynP[task] * 1200.0 - dur * 800.0;\n                util[r][c] = llround(u);\n            }\n        }\n\n        ll maxU = DUMMY_UTILITY;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                maxU = max(maxU, util[i][j]);\n            }\n        }\n\n        vector<vector<ll>> cost(n, vector<ll>(m));\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                cost[i][j] = maxU - util[i][j];\n            }\n        }\n\n        vector<int> assign = hungarian_min(cost);\n        for (int r = 0; r < n; r++) {\n            int c = assign[r];\n            if (0 <= c && c < (int)cand.size()) {\n                res.push_back({rem_members[r], cand[c]});\n            }\n        }\n\n        return res;\n    }\n\n    void run() {\n        read_input();\n        preprocess();\n\n        for (int day = 1; ; day++) {\n            auto assignments = choose_assignments(day);\n\n            // Apply assignments locally before output.\n            for (auto [j, t] : assignments) {\n                members[j].current_task = t;\n                members[j].start_day = day;\n                state[t] = 1;\n            }\n\n            cout << assignments.size();\n            for (auto [j, t] : assignments) {\n                cout << ' ' << (j + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int ncomp;\n            if (!(cin >> ncomp)) return;\n            if (ncomp == -1) return;\n\n            vector<int> finished_members(ncomp);\n            for (int i = 0; i < ncomp; i++) {\n                cin >> finished_members[i];\n                --finished_members[i];\n            }\n\n            vector<int> completed_today_tasks;\n            completed_today_tasks.reserve(ncomp);\n\n            for (int j : finished_members) {\n                if (j < 0 || j >= M) continue;\n                if (!members[j].busy()) continue;\n\n                int task = members[j].current_task;\n                int dur = day - members[j].start_day + 1;\n\n                members[j].obs.push_back({task, dur});\n                members[j].current_task = -1;\n                members[j].start_day = -1;\n\n                if (0 <= task && task < N && state[task] == 1) {\n                    state[task] = 2;\n                    completed_today_tasks.push_back(task);\n                    completed_tasks++;\n                }\n\n                reestimate_member(j);\n            }\n\n            for (int task : completed_today_tasks) {\n                for (int to : g[task]) {\n                    if (state[to] == 0) {\n                        indeg_rem[to]--;\n                    }\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing u8 = unsigned char;\n\nstatic constexpr int N = 1000;\nstatic constexpr int M = 50;\nstatic constexpr int POINTS = 2001;          // 2*N + depot\nstatic constexpr int DEPOT = 2000;\nstatic constexpr int DEPOT_X = 400;\nstatic constexpr int DEPOT_Y = 400;\nstatic constexpr int MAX_ROUTE = 110;\nstatic constexpr int INF = 1e9;\n\nstatic uint16_t distMat[POINTS][POINTS];\nstatic int PX[POINTS], PY[POINTS];\n\nchrono::steady_clock::time_point g_start;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nstruct Insertion {\n    int delta;\n    int gapP;\n    int gapD;\n    bool sameGap;\n};\n\nstruct Candidate {\n    int delta;\n    int oid;\n    Insertion ins;\n};\n\nstruct RouteContext {\n    int L = 0;\n    int E = 0;\n    int pid[MAX_ROUTE];\n    int edge[MAX_ROUTE];\n    int total = 0;\n};\n\nstruct Solution {\n    vector<int> route;            // point ids, includes depot at both ends\n    array<u8, N> sel{};\n    int cost = INF;\n};\n\ninline int pick_pid(int oid) { return oid << 1; }\ninline int del_pid(int oid) { return (oid << 1) | 1; }\n\nint calc_cost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distMat[route[i]][route[i + 1]];\n    }\n    return s;\n}\n\nvoid build_context(const vector<int>& route, RouteContext& ctx) {\n    ctx.L = (int)route.size();\n    ctx.E = ctx.L - 1;\n    ctx.total = 0;\n    for (int i = 0; i < ctx.L; i++) ctx.pid[i] = route[i];\n    for (int i = 0; i < ctx.E; i++) {\n        ctx.edge[i] = distMat[ctx.pid[i]][ctx.pid[i + 1]];\n        ctx.total += ctx.edge[i];\n    }\n}\n\nInsertion find_best_insertion(const RouteContext& ctx, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n\n    const uint16_t* Dp = distMat[p];\n    const uint16_t* Dd = distMat[d];\n    const int pd = Dp[d];\n\n    int delCost[MAX_ROUTE];\n    int suffMin[MAX_ROUTE];\n    int suffArg[MAX_ROUTE];\n\n    for (int j = 0; j < ctx.E; j++) {\n        const int u = ctx.pid[j];\n        const int v = ctx.pid[j + 1];\n        delCost[j] = (int)Dd[u] + (int)Dd[v] - ctx.edge[j];\n    }\n\n    suffMin[ctx.E] = INF;\n    suffArg[ctx.E] = -1;\n    for (int j = ctx.E - 1; j >= 0; j--) {\n        if (delCost[j] <= suffMin[j + 1]) {\n            suffMin[j] = delCost[j];\n            suffArg[j] = j;\n        } else {\n            suffMin[j] = suffMin[j + 1];\n            suffArg[j] = suffArg[j + 1];\n        }\n    }\n\n    Insertion best{INF, -1, -1, true};\n\n    for (int i = 0; i < ctx.E; i++) {\n        const int u = ctx.pid[i];\n        const int v = ctx.pid[i + 1];\n\n        // Insert pickup then delivery in the same original gap.\n        int same = (int)Dp[u] + pd + (int)Dd[v] - ctx.edge[i];\n        if (same < best.delta) {\n            best = Insertion{same, i, i, true};\n        }\n\n        // Insert delivery in a later gap.\n        if (i + 1 < ctx.E) {\n            int pickCost = (int)Dp[u] + (int)Dp[v] - ctx.edge[i];\n            int later = pickCost + suffMin[i + 1];\n            if (later < best.delta) {\n                best = Insertion{later, i, suffArg[i + 1], false};\n            }\n        }\n    }\n\n    return best;\n}\n\nvector<int> apply_insertion(const vector<int>& route, int oid, const Insertion& ins) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n\n    vector<int> res;\n    res.reserve(route.size() + 2);\n\n    for (int i = 0; i < (int)route.size(); i++) {\n        res.push_back(route[i]);\n        if (i == ins.gapP) {\n            res.push_back(p);\n            if (ins.sameGap) res.push_back(d);\n        }\n        if (!ins.sameGap && i == ins.gapD) {\n            res.push_back(d);\n        }\n    }\n    return res;\n}\n\nvector<int> remove_order_from_route(const vector<int>& route, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n    vector<int> res;\n    res.reserve(route.size() - 2);\n    for (int pid : route) {\n        if (pid != p && pid != d) res.push_back(pid);\n    }\n    return res;\n}\n\nvector<int> filter_route_without(const vector<int>& route, const array<u8, N>& removed) {\n    vector<int> res;\n    res.reserve(route.size());\n    for (int pid : route) {\n        if (pid == DEPOT) {\n            res.push_back(pid);\n        } else {\n            int oid = pid >> 1;\n            if (!removed[oid]) res.push_back(pid);\n        }\n    }\n    return res;\n}\n\nvector<int> selected_ids_from_route(const vector<int>& route) {\n    vector<int> ids;\n    ids.reserve(M);\n    for (int pid : route) {\n        if (pid != DEPOT && (pid & 1) == 0) ids.push_back(pid >> 1);\n    }\n    return ids;\n}\n\nvoid add_candidate(vector<Candidate>& bests, const Candidate& c, int K) {\n    int pos = 0;\n    while (pos < (int)bests.size() && bests[pos].delta <= c.delta) ++pos;\n    if (pos >= K) return;\n    bests.insert(bests.begin() + pos, c);\n    if ((int)bests.size() > K) bests.pop_back();\n}\n\nint pick_rcl_index(int sz, mt19937& rng) {\n    if (sz <= 1) return 0;\n    static const int W[12] = {32, 20, 14, 10, 8, 6, 4, 3, 2, 1, 1, 1};\n    int sum = 0;\n    for (int i = 0; i < sz; i++) sum += W[i];\n    int r = (int)(rng() % sum);\n    for (int i = 0; i < sz; i++) {\n        if (r < W[i]) return i;\n        r -= W[i];\n    }\n    return sz - 1;\n}\n\nSolution construct_solution(int seedOid, int rclK, mt19937& rng) {\n    Solution sol;\n    sol.route = {DEPOT, DEPOT};\n    sol.sel.fill(0);\n    sol.cost = 0;\n    int cnt = 0;\n\n    if (seedOid != -1) {\n        const int p = pick_pid(seedOid);\n        const int d = del_pid(seedOid);\n        sol.route = {DEPOT, p, d, DEPOT};\n        sol.sel[seedOid] = 1;\n        sol.cost = distMat[DEPOT][p] + distMat[p][d] + distMat[d][DEPOT];\n        cnt = 1;\n    }\n\n    for (; cnt < M; cnt++) {\n        RouteContext ctx;\n        build_context(sol.route, ctx);\n\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n    }\n\n    return sol;\n}\n\nbool pair_reinsert_sweep(Solution& sol, mt19937& rng, double deadline) {\n    vector<int> ids = selected_ids_from_route(sol.route);\n    shuffle(ids.begin(), ids.end(), rng);\n\n    bool improved = false;\n    for (int i = 0; i < (int)ids.size(); i++) {\n        if ((i & 7) == 0 && elapsed_sec() > deadline) break;\n        int oid = ids[i];\n\n        vector<int> base = remove_order_from_route(sol.route, oid);\n        RouteContext ctx;\n        build_context(base, ctx);\n        Insertion ins = find_best_insertion(ctx, oid);\n        int newCost = ctx.total + ins.delta;\n\n        if (newCost < sol.cost) {\n            sol.route = apply_insertion(base, oid, ins);\n            sol.cost = newCost;\n            improved = true;\n        }\n    }\n    return improved;\n}\n\nbool best_single_replace(Solution& sol, double deadline) {\n    vector<int> selIds = selected_ids_from_route(sol.route);\n\n    int bestCost = sol.cost;\n    int remOid = -1, addOid = -1;\n    Insertion bestIns{};\n    vector<int> bestBase;\n\n    for (int si = 0; si < (int)selIds.size(); si++) {\n        if ((si & 3) == 0 && elapsed_sec() > deadline) break;\n\n        int x = selIds[si];\n        vector<int> base = remove_order_from_route(sol.route, x);\n        RouteContext ctx;\n        build_context(base, ctx);\n\n        int localBestCost = INF;\n        int bestY = -1;\n        Insertion localIns{};\n\n        for (int y = 0; y < N; y++) {\n            if (sol.sel[y]) continue;\n            Insertion ins = find_best_insertion(ctx, y);\n            int c = ctx.total + ins.delta;\n            if (c < localBestCost) {\n                localBestCost = c;\n                bestY = y;\n                localIns = ins;\n            }\n        }\n\n        if (localBestCost < bestCost) {\n            bestCost = localBestCost;\n            remOid = x;\n            addOid = bestY;\n            bestIns = localIns;\n            bestBase = move(base);\n        }\n    }\n\n    if (remOid == -1) return false;\n\n    sol.sel[remOid] = 0;\n    sol.sel[addOid] = 1;\n    sol.route = apply_insertion(bestBase, addOid, bestIns);\n    sol.cost = bestCost;\n    return true;\n}\n\nvector<int> choose_removals(const Solution& sol, int mode, int K, mt19937& rng) {\n    K = min(K, M);\n    vector<int> selIds = selected_ids_from_route(sol.route);\n    vector<int> res;\n    res.reserve(K);\n    array<u8, N> used{};\n    used.fill(0);\n\n    auto add_oid = [&](int oid) {\n        if (!used[oid]) {\n            used[oid] = 1;\n            res.push_back(oid);\n        }\n    };\n\n    if (mode == 0) {\n        // Pure random\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int i = 0; i < K; i++) add_oid(selIds[i]);\n    } else if (mode == 1 || mode == 2) {\n        // Worst by removal saving, or mixed\n        vector<pair<int, int>> sav;\n        sav.reserve(selIds.size());\n        for (int oid : selIds) {\n            int c = calc_cost(remove_order_from_route(sol.route, oid));\n            sav.push_back({sol.cost - c, oid});\n        }\n        sort(sav.rbegin(), sav.rend());\n\n        int take = (mode == 1 ? K : max(1, K / 2));\n        for (int i = 0; i < take && i < (int)sav.size(); i++) add_oid(sav[i].second);\n\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int oid : selIds) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n    } else {\n        // Route segment based destroy\n        int L = (int)sol.route.size();\n        if (L > 2) {\n            int start = 1 + (int)(rng() % (L - 2));\n            int lim = min(L - 1, start + 2 * K + 4);\n            for (int pos = start; pos < lim; pos++) {\n                int pid = sol.route[pos];\n                if (pid == DEPOT) continue;\n                add_oid(pid >> 1);\n            }\n            if ((int)res.size() > K) {\n                shuffle(res.begin(), res.end(), rng);\n                res.resize(K);\n            }\n        }\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int oid : selIds) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n    }\n\n    return res;\n}\n\nSolution destroy_repair(const Solution& base, int mode, int K, int rclK, mt19937& rng) {\n    vector<int> rem = choose_removals(base, mode, K, rng);\n\n    Solution sol;\n    sol.sel = base.sel;\n\n    array<u8, N> removed{};\n    removed.fill(0);\n    for (int oid : rem) {\n        removed[oid] = 1;\n        sol.sel[oid] = 0;\n    }\n\n    sol.route = filter_route_without(base.route, removed);\n\n    RouteContext ctx;\n    build_context(sol.route, ctx);\n    sol.cost = ctx.total;\n\n    int cnt = M - (int)rem.size();\n    while (cnt < M) {\n        build_context(sol.route, ctx);\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n        cnt++;\n    }\n\n    return sol;\n}\n\nvoid local_opt(Solution& sol, mt19937& rng, double deadline, int reinSweeps, int replaceIters) {\n    for (int i = 0; i < reinSweeps && elapsed_sec() < deadline; i++) {\n        if (!pair_reinsert_sweep(sol, rng, deadline)) break;\n    }\n    for (int i = 0; i < replaceIters && elapsed_sec() < deadline; i++) {\n        if (!best_single_replace(sol, deadline)) break;\n        for (int j = 0; j < 2 && elapsed_sec() < deadline; j++) {\n            if (!pair_reinsert_sweep(sol, rng, deadline)) break;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 0; i < N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        PX[pick_pid(i)] = a;\n        PY[pick_pid(i)] = b;\n        PX[del_pid(i)] = c;\n        PY[del_pid(i)] = d;\n    }\n    PX[DEPOT] = DEPOT_X;\n    PY[DEPOT] = DEPOT_Y;\n\n    g_start = chrono::steady_clock::now();\n\n    // Precompute all Manhattan distances among 2001 relevant points.\n    for (int i = 0; i < POINTS; i++) {\n        for (int j = 0; j < POINTS; j++) {\n            distMat[i][j] = (uint16_t)(abs(PX[i] - PX[j]) + abs(PY[i] - PY[j]));\n        }\n    }\n\n    mt19937 rng(123456789);\n\n    vector<pair<int, int>> centerRank;\n    centerRank.reserve(N);\n    for (int oid = 0; oid < N; oid++) {\n        int p = pick_pid(oid), d = del_pid(oid);\n        int score = distMat[DEPOT][p] + distMat[p][d] + distMat[d][DEPOT];\n        centerRank.push_back({score, oid});\n    }\n    sort(centerRank.begin(), centerRank.end());\n\n    vector<int> seedPool;\n    for (int i = 0; i < min(N, 200); i++) seedPool.push_back(centerRank[i].second);\n\n    const double SEARCH_DEADLINE = 1.92;\n    const double FINAL_DEADLINE = 1.97;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto try_update = [&](Solution&& sol) {\n        if (!hasBest || sol.cost < best.cost) {\n            best = move(sol);\n            hasBest = true;\n        }\n    };\n\n    // Deterministic / semi-deterministic initial constructions.\n    {\n        Solution sol = construct_solution(-1, 1, rng);\n        local_opt(sol, rng, SEARCH_DEADLINE, 2, 1);\n        try_update(move(sol));\n    }\n\n    for (int i = 0; i < 4 && elapsed_sec() < 0.45; i++) {\n        Solution sol = construct_solution(seedPool[i], 1, rng);\n        local_opt(sol, rng, SEARCH_DEADLINE, 2, 1);\n        try_update(move(sol));\n    }\n\n    // Randomized multistart.\n    int initRuns = 0;\n    while (elapsed_sec() < 0.75 && initRuns < 10) {\n        int seed = ((rng() & 3) == 0 ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 80))]);\n        int rcl = 6 + (int)(rng() % 5); // 6..10\n        Solution sol = construct_solution(seed, rcl, rng);\n        local_opt(sol, rng, SEARCH_DEADLINE, 1, 0);\n        if (!hasBest || sol.cost < best.cost) {\n            best = move(sol);\n            hasBest = true;\n            local_opt(best, rng, SEARCH_DEADLINE, 1, 1);\n        }\n        initRuns++;\n    }\n\n    // Main LNS loop.\n    int iter = 0;\n    int stagnation = 0;\n    while (elapsed_sec() < SEARCH_DEADLINE) {\n        if ((iter % 6) == 0) {\n            local_opt(best, rng, SEARCH_DEADLINE, 1, 1);\n        }\n        if (elapsed_sec() >= SEARCH_DEADLINE) break;\n\n        Solution cand;\n        bool made = false;\n\n        // Occasionally restart from a fresh construction if stuck.\n        if (stagnation >= 14 && elapsed_sec() < 1.55) {\n            int seed = ((rng() & 3) == 0 ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 120))]);\n            cand = construct_solution(seed, 8, rng);\n            local_opt(cand, rng, SEARCH_DEADLINE, 1, 0);\n            made = true;\n            stagnation = 0;\n        }\n\n        if (!made) {\n            int mode = (int)(rng() % 4);\n            int K = 3 + (int)(rng() % 6); // 3..8\n            if (mode == 1) K = 4 + (int)(rng() % 5); // slightly stronger when removing \"worst\"\n            int rcl = 4 + (int)(rng() % 6); // 4..9\n            cand = destroy_repair(best, mode, K, rcl, rng);\n            pair_reinsert_sweep(cand, rng, SEARCH_DEADLINE);\n        }\n\n        if (cand.cost < best.cost) {\n            best = move(cand);\n            local_opt(best, rng, SEARCH_DEADLINE, 2, 1);\n            stagnation = 0;\n        } else {\n            stagnation++;\n        }\n        iter++;\n    }\n\n    // Final intensification.\n    local_opt(best, rng, FINAL_DEADLINE, 3, 3);\n\n    vector<int> ids = selected_ids_from_route(best.route);\n\n    cout << ids.size();\n    for (int oid : ids) cout << ' ' << (oid + 1);\n    cout << '\\n';\n\n    cout << best.route.size();\n    for (int pid : best.route) {\n        cout << ' ' << PX[pid] << ' ' << PY[pid];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p; // negative size for root\n    DSU() {}\n    DSU(int n) : p(n, -1) {}\n\n    int leader(int x) {\n        if (p[x] < 0) return x;\n        return p[x] = leader(p[x]);\n    }\n\n    bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (-p[a] < -p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        return true;\n    }\n\n    int size(int x) {\n        return -p[leader(x)];\n    }\n};\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> xs[i] >> ys[i];\n    }\n\n    vector<int> U(M), V(M), D(M);\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n        long long dx = xs[U[i]] - xs[V[i]];\n        long long dy = ys[U[i]] - ys[V[i]];\n        D[i] = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n    }\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    DSU adopted(N);\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        // If already connected by adopted edges, taking this edge can only add useless cycle cost.\n        if (!adopted.same(u, v)) {\n            // Compress current adopted components to 0..C-1\n            vector<int> root_id(N, -1), cid(N, -1);\n            int C = 0;\n            for (int x = 0; x < N; x++) {\n                int r = adopted.leader(x);\n                if (root_id[r] == -1) root_id[r] = C++;\n                cid[x] = root_id[r];\n            }\n\n            int cu = cid[u], cv = cid[v];\n\n            // Build future-only MST on current components, using D as predicted weight.\n            DSU uf2(C);\n            vector<vector<pair<int,int>>> tree(C); // (to, d)\n            int used = 0;\n            int useful_edges = 0;\n\n            for (int e : ord) {\n                if (e <= i) continue; // only unseen future edges\n\n                int a = cid[U[e]];\n                int b = cid[V[e]];\n                if (a == b) continue;\n\n                useful_edges++;\n                if (uf2.merge(a, b)) {\n                    tree[a].push_back({b, D[e]});\n                    tree[b].push_back({a, D[e]});\n                    used++;\n                }\n            }\n\n            // If future edges alone cannot connect the current components, this edge is mandatory.\n            if (used < C - 1) {\n                ans = 1;\n            } else {\n                // Find max D on the path between cu and cv in the future-only MST.\n                vector<int> parent(C, -1), pw(C, 0);\n                queue<int> q;\n                parent[cu] = cu;\n                q.push(cu);\n\n                while (!q.empty() && parent[cv] == -1) {\n                    int x = q.front();\n                    q.pop();\n                    for (auto [to, w] : tree[x]) {\n                        if (parent[to] != -1) continue;\n                        parent[to] = x;\n                        pw[to] = w;\n                        q.push(to);\n                    }\n                }\n\n                int mx = 0;\n                for (int cur = cv; cur != cu; cur = parent[cur]) {\n                    mx = max(mx, pw[cur]);\n                }\n\n                // Dynamic threshold:\n                // more future alternatives => smaller lambda\n                // fewer future alternatives => larger lambda\n                double density = (C <= 1 ? 10.0 : (double)useful_edges / (double)(C - 1));\n                double t = (density - 1.0) / 4.0; // around 0 when density~1, 1 when density~5\n                if (t < 0.0) t = 0.0;\n                if (t > 1.0) t = 1.0;\n\n                double lambda = 2.05 - 0.45 * t; // from 2.05 down to 1.60\n\n                if ((double)l <= lambda * (double)mx + 1e-9) {\n                    ans = 1;\n                } else {\n                    ans = 0;\n                }\n            }\n        } else {\n            ans = 0;\n        }\n\n        cout << ans << '\\n' << flush;\n        if (ans) adopted.merge(u, v);\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int S = 30;\nstatic constexpr int MAX_TURN = 300;\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar moveChar[4] = {'U', 'D', 'L', 'R'};\nchar buildCharLower[4] = {'u', 'd', 'l', 'r'};\n\nstruct Task {\n    int wr, wc;   // wall cell to block\n    int sr, sc;   // stance cell to stand on\n    char act;     // build action\n};\n\nstruct Room {\n    int r1, r2, c1, c2;      // inside rectangle inclusive\n    int br, bc;              // horizontal/vertical barrier lines\n    int doorR, doorC;        // the last door cell to close\n    int inDoorR, inDoorC;    // inside-adjacent cell for closing the door\n    int centerR, centerC;    // room center\n    char doorAct;            // action to close the door\n    vector<Task> tasks;      // all wall cells except the final door\n\n    bool inside(int r, int c) const {\n        return r1 <= r && r <= r2 && c1 <= c && c <= c2;\n    }\n    int area() const {\n        return (r2 - r1 + 1) * (c2 - c1 + 1);\n    }\n};\n\nstruct BFSRes {\n    int dist[S][S];\n    char first[S][S];\n    BFSRes() {\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < S; j++) {\n                dist[i][j] = -1;\n                first[i][j] = 0;\n            }\n        }\n    }\n};\n\nint N, M;\nvector<pair<int,int>> petsPos;\nvector<int> petsType;\nvector<pair<int,int>> humansPos;\n\narray<array<bool, S>, S> wallCell;\n\ninline bool inb(int r, int c) {\n    return 0 <= r && r < S && 0 <= c && c < S;\n}\n\npair<int,int> apply_dir(pair<int,int> p, char ch) {\n    if (ch == 'U' || ch == 'u') return {p.first - 1, p.second};\n    if (ch == 'D' || ch == 'd') return {p.first + 1, p.second};\n    if (ch == 'L' || ch == 'l') return {p.first, p.second - 1};\n    if (ch == 'R' || ch == 'r') return {p.first, p.second + 1};\n    return p;\n}\n\nRoom make_room(int corner, int H, int W) {\n    // corner: 0 TL, 1 TR, 2 BL, 3 BR\n    bool top = (corner == 0 || corner == 1);\n    bool left = (corner == 0 || corner == 2);\n\n    Room room;\n    if (top) {\n        room.r1 = 0;\n        room.r2 = H - 1;\n        room.br = H;\n        room.inDoorR = H - 1;\n        room.doorAct = 'd';\n    } else {\n        room.r1 = S - H;\n        room.r2 = S - 1;\n        room.br = S - H - 1;\n        room.inDoorR = S - H;\n        room.doorAct = 'u';\n    }\n\n    if (left) {\n        room.c1 = 0;\n        room.c2 = W - 1;\n        room.bc = W;\n    } else {\n        room.c1 = S - W;\n        room.c2 = S - 1;\n        room.bc = S - W - 1;\n    }\n\n    room.doorC = (room.c1 + room.c2) / 2;\n    room.doorR = room.br;\n    room.inDoorC = room.doorC;\n    room.centerR = (room.r1 + room.r2) / 2;\n    room.centerC = (room.c1 + room.c2) / 2;\n\n    room.tasks.clear();\n\n    // Horizontal barrier except the door\n    for (int c = room.c1; c <= room.c2; c++) {\n        if (c == room.doorC) continue;\n        Task t;\n        t.wr = room.br; t.wc = c;\n        t.sr = room.inDoorR; t.sc = c;\n        t.act = room.doorAct;\n        room.tasks.push_back(t);\n    }\n\n    // Vertical barrier\n    int insideCol = left ? room.c2 : room.c1;\n    char vAct = left ? 'r' : 'l';\n    for (int r = room.r1; r <= room.r2; r++) {\n        Task t;\n        t.wr = r; t.wc = room.bc;\n        t.sr = r; t.sc = insideCol;\n        t.act = vAct;\n        room.tasks.push_back(t);\n    }\n\n    return room;\n}\n\nint dist_to_rect(const Room& room, int r, int c) {\n    int vr = 0, vc = 0;\n    if (r < room.r1) vr = room.r1 - r;\n    else if (r > room.r2) vr = r - room.r2;\n    if (c < room.c1) vc = room.c1 - c;\n    else if (c > room.c2) vc = c - room.c2;\n    return vr + vc;\n}\n\nRoom choose_room() {\n    vector<pair<int,int>> cand = {\n        {8, 8}, {8, 10}, {10, 8}, {10, 10},\n        {10, 12}, {12, 10}, {12, 12}, {12, 14}, {14, 12}\n    };\n\n    double bestScore = -1e100;\n    Room bestRoom = make_room(0, 10, 10);\n\n    for (auto [H, W] : cand) {\n        for (int corner = 0; corner < 4; corner++) {\n            Room room = make_room(corner, H, W);\n\n            int insidePets = 0;\n            int insideDogs = 0;\n            for (int i = 0; i < N; i++) {\n                auto [r, c] = petsPos[i];\n                if (room.inside(r, c)) {\n                    insidePets++;\n                    if (petsType[i] == 4) insideDogs++;\n                }\n            }\n\n            int sumDist = 0;\n            for (int i = 0; i < M; i++) {\n                auto [r, c] = humansPos[i];\n                sumDist += dist_to_rect(room, r, c);\n            }\n\n            // Heuristic:\n            // larger area is good, but pets/dogs inside are heavily bad.\n            double score = room.area();\n            score *= pow(0.6, insidePets);\n            score *= pow(0.6, insideDogs);\n            score -= 0.15 * sumDist;\n\n            if (score > bestScore) {\n                bestScore = score;\n                bestRoom = room;\n            }\n        }\n    }\n    return bestRoom;\n}\n\nBFSRes bfs_from(pair<int,int> st, const array<array<bool, S>, S>& blocked) {\n    BFSRes res;\n    queue<pair<int,int>> q;\n    auto [sr, sc] = st;\n    res.dist[sr][sc] = 0;\n    res.first[sr][sc] = '.';\n    q.push(st);\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n        for (int k = 0; k < 4; k++) {\n            int nr = r + dr[k], nc = c + dc[k];\n            if (!inb(nr, nc)) continue;\n            if (blocked[nr][nc]) continue;\n            if (res.dist[nr][nc] != -1) continue;\n            res.dist[nr][nc] = res.dist[r][c] + 1;\n            res.first[nr][nc] = (res.dist[r][c] == 0 ? moveChar[k] : res.first[r][c]);\n            q.push({nr, nc});\n        }\n    }\n    return res;\n}\n\nbool can_block_cell(int tr, int tc,\n                    const array<array<int, S>, S>& humanCnt,\n                    const array<array<int, S>, S>& petCnt) {\n    if (!inb(tr, tc)) return false;\n    if (humanCnt[tr][tc] > 0) return false;\n    if (petCnt[tr][tc] > 0) return false;\n    for (int k = 0; k < 4; k++) {\n        int nr = tr + dr[k], nc = tc + dc[k];\n        if (!inb(nr, nc)) continue;\n        if (petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nvoid rebuild_counts(array<array<int, S>, S>& humanCnt,\n                    array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            humanCnt[i][j] = 0;\n            petCnt[i][j] = 0;\n        }\n    }\n    for (auto [r, c] : humansPos) humanCnt[r][c]++;\n    for (auto [r, c] : petsPos) petCnt[r][c]++;\n}\n\nbool all_humans_inside(const Room& room) {\n    for (auto [r, c] : humansPos) {\n        if (!room.inside(r, c)) return false;\n    }\n    return true;\n}\n\nint pets_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : petsPos) {\n        if (room.inside(r, c)) cnt++;\n    }\n    return cnt;\n}\n\nbool unfinished_exists(const Room& room) {\n    for (auto &t : room.tasks) {\n        if (!wallCell[t.wr][t.wc]) return true;\n    }\n    return false;\n}\n\nbool should_close_now(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 240 && petsInside <= 1) return true;\n    if (turn >= 270 && petsInside <= 2) return true;\n    if (turn >= 290 && petsInside <= 3) return true;\n    if (turn >= 298) return true;\n    return false;\n}\n\nstring plan_build_actions(const Room& room,\n                          const array<array<int, S>, S>& humanCnt,\n                          const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n\n    vector<int> unfinished;\n    for (int i = 0; i < (int)room.tasks.size(); i++) {\n        auto &t = room.tasks[i];\n        if (!wallCell[t.wr][t.wc]) unfinished.push_back(i);\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    vector<bool> humanUsed(M, false);\n    vector<bool> taskUsed(room.tasks.size(), false);\n\n    // First: if already on a stance and legal, build immediately.\n    for (int i = 0; i < M; i++) {\n        auto [hr, hc] = humansPos[i];\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                if (can_block_cell(t.wr, t.wc, humanCnt, petCnt) && !toBlock[t.wr][t.wc]) {\n                    act[i] = t.act;\n                    humanUsed[i] = true;\n                    taskUsed[idx] = true;\n                    toBlock[t.wr][t.wc] = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    array<array<bool, S>, S> blocked = wallCell;\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) blocked[i][j] = true;\n        }\n    }\n\n    vector<BFSRes> bfsRes(M);\n    for (int i = 0; i < M; i++) {\n        if (!humanUsed[i]) bfsRes[i] = bfs_from(humansPos[i], blocked);\n    }\n\n    vector<int> assignedTask(M, -1);\n\n    // Greedy matching: nearest human -> unfinished task\n    while (true) {\n        int bestH = -1, bestT = -1, bestD = 1e9;\n        for (int i = 0; i < M; i++) {\n            if (humanUsed[i]) continue;\n            for (int idx : unfinished) {\n                if (taskUsed[idx]) continue;\n                auto &t = room.tasks[idx];\n                int d = bfsRes[i].dist[t.sr][t.sc];\n                if (d <= 0) continue; // exclude unreachable / already on stance (but not buildable)\n                if (d < bestD) {\n                    bestD = d;\n                    bestH = i;\n                    bestT = idx;\n                }\n            }\n        }\n        if (bestH == -1) break;\n        humanUsed[bestH] = true;\n        taskUsed[bestT] = true;\n        assignedTask[bestH] = bestT;\n    }\n\n    // Moves for assigned humans\n    for (int i = 0; i < M; i++) {\n        if (assignedTask[i] != -1) {\n            auto &t = room.tasks[assignedTask[i]];\n            char mv = bfsRes[i].first[t.sr][t.sc];\n            if (mv) act[i] = mv;\n        }\n    }\n\n    // Fallback for still-idle humans\n    for (int i = 0; i < M; i++) {\n        if (act[i] != '.') continue;\n\n        auto [hr, hc] = humansPos[i];\n        bool onSomeUnfinishedStance = false;\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                onSomeUnfinishedStance = true;\n                break;\n            }\n        }\n        if (onSomeUnfinishedStance) continue; // stay and wait\n\n        BFSRes b = bfs_from(humansPos[i], blocked);\n        int d = b.dist[room.centerR][room.centerC];\n        if (d > 0) act[i] = b.first[room.centerR][room.centerC];\n    }\n\n    return act;\n}\n\nstring plan_wait_actions(const Room& room, int turn,\n                         const array<array<int, S>, S>& humanCnt,\n                         const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n\n    int petsInside = pets_inside_count(room);\n    bool allInside = all_humans_inside(room);\n\n    // If possible, close now.\n    if (allInside && should_close_now(turn, petsInside) &&\n        can_block_cell(room.doorR, room.doorC, humanCnt, petCnt)) {\n        for (int i = 0; i < M; i++) {\n            auto [r, c] = humansPos[i];\n            if (r == room.inDoorR && c == room.inDoorC) {\n                act[i] = room.doorAct;\n                return act;\n            }\n        }\n    }\n\n    // Otherwise move humans.\n    array<array<bool, S>, S> blocked = wallCell;\n    vector<BFSRes> bfsRes(M);\n    for (int i = 0; i < M; i++) bfsRes[i] = bfs_from(humansPos[i], blocked);\n\n    bool wantLeaderAtDoor = (petsInside == 0) || (turn >= 220);\n    int leader = -1;\n    if (wantLeaderAtDoor) {\n        int best = 1e9;\n        for (int i = 0; i < M; i++) {\n            int d = bfsRes[i].dist[room.inDoorR][room.inDoorC];\n            if (d >= 0 && d < best) {\n                best = d;\n                leader = i;\n            }\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        int tr = room.centerR, tc = room.centerC;\n        if (i == leader) {\n            tr = room.inDoorR;\n            tc = room.inDoorC;\n        }\n        int d = bfsRes[i].dist[tr][tc];\n        if (d > 0) {\n            act[i] = bfsRes[i].first[tr][tc];\n        }\n    }\n\n    return act;\n}\n\nvoid apply_human_actions(const string& act) {\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    // Determine blocked cells\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if ('a' <= a && a <= 'z') {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc)) toBlock[nr][nc] = true;\n        }\n    }\n\n    // Build walls first\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) wallCell[i][j] = true;\n        }\n    }\n\n    // Then move humans\n    vector<pair<int,int>> newHumans = humansPos;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if ('A' <= a && a <= 'Z') {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc) && !wallCell[nr][nc]) {\n                newHumans[i] = {nr, nc};\n            }\n        }\n    }\n    humansPos.swap(newHumans);\n}\n\nvoid apply_pet_moves(const vector<string>& petMoves) {\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        for (char ch : petMoves[i]) {\n            if (ch == '.') continue;\n            auto [nr, nc] = apply_dir({r, c}, ch);\n            r = nr; c = nc;\n        }\n        petsPos[i] = {r, c};\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    petsPos.resize(N);\n    petsType.resize(N);\n    for (int i = 0; i < N; i++) {\n        int x, y, t;\n        cin >> x >> y >> t;\n        --x; --y;\n        petsPos[i] = {x, y};\n        petsType[i] = t;\n    }\n\n    cin >> M;\n    humansPos.resize(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        --x; --y;\n        humansPos[i] = {x, y};\n    }\n\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) wallCell[i][j] = false;\n\n    Room room = choose_room();\n\n    for (int turn = 0; turn < MAX_TURN; turn++) {\n        array<array<int, S>, S> humanCnt, petCnt;\n        rebuild_counts(humanCnt, petCnt);\n\n        string act(M, '.');\n\n        bool doorClosed = wallCell[room.doorR][room.doorC];\n        if (doorClosed) {\n            act = string(M, '.');\n        } else if (unfinished_exists(room)) {\n            act = plan_build_actions(room, humanCnt, petCnt);\n        } else {\n            act = plan_wait_actions(room, turn, humanCnt, petCnt);\n        }\n\n        cout << act << '\\n' << flush;\n\n        apply_human_actions(act);\n\n        vector<string> petMoves(N);\n        for (int i = 0; i < N; i++) {\n            if (!(cin >> petMoves[i])) return 0;\n        }\n        apply_pet_moves(petMoves);\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nconstexpr int N = 20;\nconstexpr int V = N * N;\nconstexpr int LMAX = 200;\nconstexpr int NONE = 4;\nconstexpr double EPS = 1e-12;\n\nconst char ACT[4] = {'U', 'D', 'L', 'R'};\nconst int di[4] = {-1, 1, 0, 0};\nconst int dj[4] = {0, 0, -1, 1};\nconst int prefDirOrder[4] = {1, 3, 0, 2}; // D,R,U,L\nconst int isUL[4] = {1, 0, 1, 0};\n\nint si, sj, ti, tj, sid, tid;\ndouble p_forget, p_move;\n\nstring H[N];\nstring VW[N - 1];\n\nint toCell[V][4];\nunsigned char transKind[V][4]; // 0: stay, 1: move, 2: hit target\nvector<int> neighbors[V];\n\nint distToT[V];\nbool spValid[V][4];\n\ndouble hitReward[LMAX + 1];\ndouble UB[LMAX + 2][V];\n\ndouble preDist[LMAX + 1][V];\ndouble sufVal[LMAX + 2][V];\ndouble prefScore[LMAX + 1];\n\nint dpMinTurn[V][5];\nint dpMaxTurn[V][5];\n\ninline int ID(int i, int j) { return i * N + j; }\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\ninline double dot400(const double* a, const double* b) {\n    double s = 0.0;\n    for (int i = 0; i < V; i++) s += a[i] * b[i];\n    return s;\n}\n\nvoid buildTransitions() {\n    for (int c = 0; c < V; c++) neighbors[c].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = ID(i, j);\n\n            // U\n            if (i > 0 && VW[i - 1][j] == '0') toCell[c][0] = ID(i - 1, j);\n            else toCell[c][0] = c;\n\n            // D\n            if (i < N - 1 && VW[i][j] == '0') toCell[c][1] = ID(i + 1, j);\n            else toCell[c][1] = c;\n\n            // L\n            if (j > 0 && H[i][j - 1] == '0') toCell[c][2] = ID(i, j - 1);\n            else toCell[c][2] = c;\n\n            // R\n            if (j < N - 1 && H[i][j] == '0') toCell[c][3] = ID(i, j + 1);\n            else toCell[c][3] = c;\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            int nc = toCell[c][a];\n            if (nc != c) neighbors[c].push_back(nc);\n        }\n        sort(neighbors[c].begin(), neighbors[c].end());\n        neighbors[c].erase(unique(neighbors[c].begin(), neighbors[c].end()), neighbors[c].end());\n    }\n\n    // Absorbing target for safety in value DP\n    for (int a = 0; a < 4; a++) toCell[tid][a] = tid;\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c == tid) {\n                transKind[c][a] = 0;\n            } else if (toCell[c][a] == c) {\n                transKind[c][a] = 0;\n            } else if (toCell[c][a] == tid) {\n                transKind[c][a] = 2;\n            } else {\n                transKind[c][a] = 1;\n            }\n        }\n    }\n}\n\nvoid bfsDistToTarget() {\n    fill(distToT, distToT + V, -1);\n    queue<int> q;\n    distToT[tid] = 0;\n    q.push(tid);\n\n    while (!q.empty()) {\n        int c = q.front();\n        q.pop();\n        for (int nc : neighbors[c]) {\n            if (distToT[nc] == -1) {\n                distToT[nc] = distToT[c] + 1;\n                q.push(nc);\n            }\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c != tid && transKind[c][a] != 0) {\n                int nc = toCell[c][a];\n                spValid[c][a] = (distToT[nc] == distToT[c] - 1);\n            } else {\n                spValid[c][a] = false;\n            }\n        }\n    }\n}\n\nvoid computeAdaptiveUpperBound() {\n    for (int c = 0; c < V; c++) UB[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        UB[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                double val = 0.0;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val = UB[t + 1][c];\n                } else if (k == 2) {\n                    val = hitReward[t] + p_forget * UB[t + 1][c];\n                } else {\n                    int nc = toCell[c][a];\n                    val = p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc];\n                }\n                if (val > best) best = val;\n            }\n            UB[t][c] = best;\n        }\n    }\n}\n\nvector<int> greedyRollout() {\n    vector<int> seq(LMAX, 0);\n    array<double, V> dist{};\n    dist.fill(0.0);\n    dist[sid] = 1.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        int bestA = 0;\n        double bestVal = -1e100;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            double val = 0.0;\n            for (int c = 0; c < V; c++) {\n                double q = dist[c];\n                if (q < 1e-18) continue;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val += q * UB[t + 1][c];\n                } else if (k == 2) {\n                    val += q * (hitReward[t] + p_forget * UB[t + 1][c]);\n                } else {\n                    int nc = toCell[c][a];\n                    val += q * (p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc]);\n                }\n            }\n            if (val > bestVal + 1e-15) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq[t - 1] = bestA;\n\n        array<double, V> nd{};\n        nd.fill(0.0);\n        for (int c = 0; c < V; c++) {\n            double q = dist[c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][bestA];\n            if (k == 0) {\n                nd[c] += q;\n            } else if (k == 2) {\n                nd[c] += q * p_forget;\n            } else {\n                int nc = toCell[c][bestA];\n                nd[c] += q * p_forget;\n                nd[nc] += q * p_move;\n            }\n        }\n        dist = nd;\n    }\n\n    return seq;\n}\n\nstruct CurState {\n    array<double, V> dist;\n    double score;\n};\n\nstruct CandState {\n    array<double, V> dist;\n    double score;\n    double pri;\n    int parent;\n    unsigned char act;\n};\n\nstruct ParentInfo {\n    int parent;\n    unsigned char act;\n};\n\nvector<vector<int>> beamSearch(int beamWidth, int topM) {\n    vector<vector<ParentInfo>> parent(LMAX + 1);\n\n    vector<CurState> cur, nxt;\n    cur.reserve(beamWidth);\n    nxt.reserve(beamWidth);\n\n    CurState start;\n    start.dist.fill(0.0);\n    start.dist[sid] = 1.0;\n    start.score = 0.0;\n    cur.push_back(start);\n\n    vector<CandState> cand;\n    cand.reserve(beamWidth * 4);\n    vector<int> ord;\n\n    for (int t = 1; t <= LMAX; t++) {\n        cand.clear();\n\n        for (int idx = 0; idx < (int)cur.size(); idx++) {\n            const auto &st = cur[idx];\n            for (int a = 0; a < 4; a++) {\n                CandState cs;\n                cs.dist.fill(0.0);\n                cs.parent = idx;\n                cs.act = (unsigned char)a;\n                double scoreAfter = st.score;\n                double pri = st.score;\n\n                for (int c = 0; c < V; c++) {\n                    double q = st.dist[c];\n                    if (q < 1e-18) continue;\n                    unsigned char k = transKind[c][a];\n                    if (k == 0) {\n                        cs.dist[c] += q;\n                        pri += q * UB[t + 1][c];\n                    } else if (k == 2) {\n                        cs.dist[c] += q * p_forget;\n                        scoreAfter += q * hitReward[t];\n                        pri += q * (hitReward[t] + p_forget * UB[t + 1][c]);\n                    } else {\n                        int nc = toCell[c][a];\n                        cs.dist[c] += q * p_forget;\n                        cs.dist[nc] += q * p_move;\n                        pri += q * (p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc]);\n                    }\n                }\n\n                cs.score = scoreAfter;\n                cs.pri = pri;\n                cand.push_back(std::move(cs));\n            }\n        }\n\n        int k = min(beamWidth, (int)cand.size());\n        ord.resize(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n\n        auto cmp = [&](int x, int y) {\n            if (cand[x].pri != cand[y].pri) return cand[x].pri > cand[y].pri;\n            if (cand[x].score != cand[y].score) return cand[x].score > cand[y].score;\n            if (cand[x].parent != cand[y].parent) return cand[x].parent < cand[y].parent;\n            return cand[x].act < cand[y].act;\n        };\n        partial_sort(ord.begin(), ord.begin() + k, ord.end(), cmp);\n\n        nxt.clear();\n        parent[t].resize(k);\n        for (int i = 0; i < k; i++) {\n            int id = ord[i];\n            CurState ns;\n            ns.dist = cand[id].dist;\n            ns.score = cand[id].score;\n            nxt.push_back(std::move(ns));\n            parent[t][i] = ParentInfo{cand[id].parent, cand[id].act};\n        }\n        cur.swap(nxt);\n    }\n\n    vector<int> finalOrd(cur.size());\n    iota(finalOrd.begin(), finalOrd.end(), 0);\n    sort(finalOrd.begin(), finalOrd.end(), [&](int x, int y) {\n        if (cur[x].score != cur[y].score) return cur[x].score > cur[y].score;\n        return x < y;\n    });\n\n    vector<vector<int>> res;\n    topM = min(topM, (int)finalOrd.size());\n    for (int z = 0; z < topM; z++) {\n        int idx = finalOrd[z];\n        vector<int> seq(LMAX);\n        for (int t = LMAX; t >= 1; t--) {\n            seq[t - 1] = parent[t][idx].act;\n            idx = parent[t][idx].parent;\n        }\n        res.push_back(std::move(seq));\n    }\n    return res;\n}\n\nvector<int> buildShortestPathByTurns(bool maximizeTurns) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return distToT[a] < distToT[b];\n    });\n\n    const int INF = 1e9;\n\n    for (int c : ids) {\n        for (int last = 0; last < 5; last++) {\n            if (c == tid) {\n                dpMinTurn[c][last] = 0;\n                dpMaxTurn[c][last] = 0;\n                continue;\n            }\n\n            int bestMin = INF;\n            int bestMax = -INF;\n\n            for (int a = 0; a < 4; a++) {\n                if (!spValid[c][a]) continue;\n                int nc = toCell[c][a];\n                int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n                bestMin = min(bestMin, turnCost + isUL[a] + dpMinTurn[nc][a]);\n                bestMax = max(bestMax, turnCost - isUL[a] + dpMaxTurn[nc][a]);\n            }\n\n            dpMinTurn[c][last] = bestMin;\n            dpMaxTurn[c][last] = bestMax;\n        }\n    }\n\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n\n    while (c != tid) {\n        int bestA = -1;\n        int bestVal = maximizeTurns ? -INF : INF;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n            int val;\n            if (maximizeTurns) {\n                val = turnCost - isUL[a] + dpMaxTurn[nc][a];\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            } else {\n                val = turnCost + isUL[a] + dpMinTurn[nc][a];\n                if (val < bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            }\n        }\n\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n\n    return path;\n}\n\nvector<int> repeatPathTo200(const vector<int> &path) {\n    vector<int> seq(LMAX, 1);\n    if (path.empty()) return seq;\n    for (int t = 0; t < LMAX; t++) seq[t] = path[t % (int)path.size()];\n    return seq;\n}\n\nvector<int> makePeriodic(const vector<int>& pat) {\n    vector<int> seq(LMAX);\n    for (int t = 0; t < LMAX; t++) seq[t] = pat[t % (int)pat.size()];\n    return seq;\n}\n\nvector<int> randomWeightedShortestPath(XorShift64& rng, double wTurn, double wBlock, double noise) {\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n    while (c != tid) {\n        int bestA = -1;\n        double bestS = -1e100;\n        for (int a = 0; a < 4; a++) {\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            double s = 0.0;\n            if (last != NONE && last != a) s += wTurn;\n            if (nc == tid || toCell[nc][a] == nc) s += wBlock;\n            s += noise * rng.nextDouble();\n            if (s > bestS) {\n                bestS = s;\n                bestA = a;\n            }\n        }\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n    return path;\n}\n\nvoid computeForward(const vector<int> &seq) {\n    fill(preDist[0], preDist[0] + V, 0.0);\n    preDist[0][sid] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        fill(preDist[t], preDist[t] + V, 0.0);\n        int a = seq[t - 1];\n        double sc = prefScore[t - 1];\n\n        for (int c = 0; c < V; c++) {\n            double q = preDist[t - 1][c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                preDist[t][c] += q;\n            } else if (k == 2) {\n                preDist[t][c] += q * p_forget;\n                sc += q * hitReward[t];\n            } else {\n                int nc = toCell[c][a];\n                preDist[t][c] += q * p_forget;\n                preDist[t][nc] += q * p_move;\n            }\n        }\n        prefScore[t] = sc;\n    }\n}\n\ndouble exactScore(const vector<int>& seq) {\n    computeForward(seq);\n    return prefScore[LMAX];\n}\n\nvoid computeBackward(const vector<int> &seq) {\n    for (int c = 0; c < V; c++) sufVal[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        int a = seq[t - 1];\n        sufVal[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                sufVal[t][c] = sufVal[t + 1][c];\n            } else if (k == 2) {\n                sufVal[t][c] = hitReward[t] + p_forget * sufVal[t + 1][c];\n            } else {\n                int nc = toCell[c][a];\n                sufVal[t][c] = p_forget * sufVal[t + 1][c] + p_move * sufVal[t + 1][nc];\n            }\n        }\n    }\n}\n\ninline void applyActionValue(int pos, int a, const double* next, double* out) {\n    out[tid] = 0.0;\n    for (int c = 0; c < V; c++) {\n        if (c == tid) continue;\n        unsigned char k = transKind[c][a];\n        if (k == 0) {\n            out[c] = next[c];\n        } else if (k == 2) {\n            out[c] = hitReward[pos] + p_forget * next[c];\n        } else {\n            int nc = toCell[c][a];\n            out[c] = p_forget * next[c] + p_move * next[nc];\n        }\n    }\n}\n\nstruct Change {\n    int k = 0;\n    int pos = -1; // 0-based\n    int a[3] = {0, 0, 0};\n    double score = -1e100;\n};\n\nChange searchBest1(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double out[V];\n\n    for (int t = 1; t <= LMAX; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n        const double* nxt = sufVal[t + 1];\n\n        for (int a = 0; a < 4; a++) {\n            if (a == seq[t - 1]) continue;\n            applyActionValue(t, a, nxt, out);\n            double val = base + dot400(pre, out);\n            if (val > best.score + EPS) {\n                best.score = val;\n                best.k = 1;\n                best.pos = t - 1;\n                best.a[0] = a;\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest2(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double mid[4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 1; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        for (int b = 0; b < 4; b++) applyActionValue(t + 1, b, sufVal[t + 2], mid[b]);\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                if (a == seq[t - 1] && b == seq[t]) continue;\n                applyActionValue(t, a, mid[b], out);\n                double val = base + dot400(pre, out);\n                if (val > best.score + EPS) {\n                    best.score = val;\n                    best.k = 2;\n                    best.pos = t - 1;\n                    best.a[0] = a;\n                    best.a[1] = b;\n                }\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest3(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double tail[4][V];\n    static double mid[4][4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 2; t++) {\n        if ((t & 7) == 0 && Clock::now() >= deadline) break;\n\n        for (int c = 0; c < 4; c++) applyActionValue(t + 2, c, sufVal[t + 3], tail[c]);\n        for (int b = 0; b < 4; b++) {\n            for (int c = 0; c < 4; c++) {\n                applyActionValue(t + 1, b, tail[c], mid[b][c]);\n            }\n        }\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                for (int c = 0; c < 4; c++) {\n                    if (a == seq[t - 1] && b == seq[t] && c == seq[t + 1]) continue;\n                    applyActionValue(t, a, mid[b][c], out);\n                    double val = base + dot400(pre, out);\n                    if (val > best.score + EPS) {\n                        best.score = val;\n                        best.k = 3;\n                        best.pos = t - 1;\n                        best.a[0] = a;\n                        best.a[1] = b;\n                        best.a[2] = c;\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\ndouble localDescent(vector<int>& seq, const Clock::time_point& deadline, int maxIter, bool allow3) {\n    computeForward(seq);\n    double curScore = prefScore[LMAX];\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (Clock::now() >= deadline) break;\n        computeBackward(seq);\n\n        Change best = searchBest1(seq, curScore, deadline);\n        if (Clock::now() >= deadline) break;\n\n        Change c2 = searchBest2(seq, curScore, deadline);\n        if (c2.score > best.score + EPS) best = c2;\n\n        if (allow3 && best.k == 0 && iter < 8) {\n            if (Clock::now() + chrono::milliseconds(60) < deadline) {\n                Change c3 = searchBest3(seq, curScore, deadline);\n                if (c3.score > best.score + EPS) best = c3;\n            }\n        }\n\n        if (best.k == 0) break;\n\n        for (int i = 0; i < best.k; i++) seq[best.pos + i] = best.a[i];\n        computeForward(seq);\n        curScore = prefScore[LMAX];\n    }\n\n    return curScore;\n}\n\nstring seqToString(const vector<int>& seq) {\n    string s;\n    s.reserve(seq.size());\n    for (int a : seq) s.push_back(ACT[a]);\n    return s;\n}\n\nvoid perturb(vector<int>& seq, const vector<vector<int>>& pool, XorShift64& rng) {\n    int mode = rng.nextInt(4);\n\n    if (mode == 0) {\n        int len = 1 + rng.nextInt(8);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[pos + i] = rng.nextInt(4);\n    } else if (mode == 1 && !pool.empty()) {\n        int len = 5 + rng.nextInt(26);\n        len = min(len, LMAX);\n        int dst = rng.nextInt(LMAX - len + 1);\n        const auto& src = pool[rng.nextInt((int)pool.size())];\n        int srcPos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[dst + i] = src[srcPos + i];\n    } else if (mode == 2) {\n        int cnt = 2 + rng.nextInt(5);\n        for (int k = 0; k < cnt; k++) {\n            int pos = rng.nextInt(LMAX);\n            seq[pos] = rng.nextInt(4);\n        }\n    } else {\n        int len = 3 + rng.nextInt(12);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) {\n            if (rng.nextInt(3) == 0) seq[pos + i] = rng.nextInt(4);\n        }\n    }\n}\n\nuint64_t makeSeed() {\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(si); mix(sj); mix(ti); mix(tj);\n    mix((uint64_t)llround(p_forget * 1000.0));\n    for (int i = 0; i < N; i++) {\n        for (char ch : H[i]) mix((uint64_t)ch);\n    }\n    for (int i = 0; i < N - 1; i++) {\n        for (char ch : VW[i]) mix((uint64_t)ch);\n    }\n    return seed;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto globalStart = Clock::now();\n    auto deadline = globalStart + chrono::milliseconds(1950);\n\n    cin >> si >> sj >> ti >> tj >> p_forget;\n    for (int i = 0; i < N; i++) cin >> H[i];\n    for (int i = 0; i < N - 1; i++) cin >> VW[i];\n\n    sid = ID(si, sj);\n    tid = ID(ti, tj);\n    p_move = 1.0 - p_forget;\n\n    for (int t = 1; t <= LMAX; t++) hitReward[t] = p_move * (401 - t);\n\n    buildTransitions();\n    bfsDistToTarget();\n    computeAdaptiveUpperBound();\n\n    XorShift64 rng(makeSeed());\n\n    vector<vector<int>> candidates;\n    candidates.reserve(32);\n\n    // Heuristic rollout / beam\n    candidates.push_back(greedyRollout());\n    {\n        auto beams = beamSearch(90, 3);\n        for (auto& s : beams) candidates.push_back(s);\n    }\n\n    // Shortest-path extremes\n    candidates.push_back(repeatPathTo200(buildShortestPathByTurns(false)));\n    candidates.push_back(repeatPathTo200(buildShortestPathByTurns(true)));\n\n    // Randomized shortest-path variants\n    {\n        vector<tuple<double, double, double>> params = {\n            {-3.0, 0.0, 0.8},\n            { 3.0, 0.0, 0.8},\n            {-1.0, 2.0, 0.8},\n            { 1.0, 2.0, 0.8},\n            { 0.0, 3.0, 0.8},\n            {-2.0, 1.0, 1.5},\n            { 2.0, 1.0, 1.5},\n            { 0.0, 0.0, 2.0}\n        };\n        for (auto [wt, wb, nz] : params) {\n            auto pth = randomWeightedShortestPath(rng, wt, wb, nz);\n            candidates.push_back(repeatPathTo200(pth));\n        }\n    }\n\n    // Simple periodic baselines\n    candidates.push_back(makePeriodic({1, 3}));       // DRDR...\n    candidates.push_back(makePeriodic({3, 1}));       // RDRD...\n    candidates.push_back(makePeriodic({1, 1, 3, 3})); // DDRR...\n    candidates.push_back(makePeriodic({3, 3, 1, 1})); // RRDD...\n\n    // Deduplicate\n    unordered_set<string> seen;\n    vector<vector<int>> uniq;\n    uniq.reserve(candidates.size());\n    for (auto& seq : candidates) {\n        string key = seqToString(seq);\n        if (seen.insert(key).second) uniq.push_back(seq);\n    }\n\n    vector<pair<double, int>> order;\n    order.reserve(uniq.size());\n    for (int i = 0; i < (int)uniq.size(); i++) {\n        double sc = exactScore(uniq[i]);\n        order.push_back({sc, i});\n    }\n    sort(order.begin(), order.end(), greater<pair<double, int>>());\n\n    vector<int> bestSeq = uniq[order[0].second];\n    double bestScore = order[0].first;\n\n    vector<vector<int>> pool;\n    for (int z = 0; z < (int)order.size() && z < 8; z++) {\n        pool.push_back(uniq[order[z].second]);\n    }\n\n    // Improve top seeds\n    int topTrials = min(5, (int)order.size());\n    for (int z = 0; z < topTrials; z++) {\n        if (Clock::now() >= deadline) break;\n        vector<int> seq = uniq[order[z].second];\n        bool allow3 = (z == 0);\n        int maxIter = (z == 0 ? 30 : 18);\n        double sc = localDescent(seq, deadline, maxIter, allow3);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n        if ((int)pool.size() < 16) pool.push_back(seq);\n    }\n\n    // Final polish on current best\n    if (Clock::now() + chrono::milliseconds(80) < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = localDescent(seq, deadline, 20, true);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    // Perturb + re-descent\n    while (Clock::now() + chrono::milliseconds(50) < deadline) {\n        vector<int> seq = bestSeq;\n        perturb(seq, pool, rng);\n        double sc = localDescent(seq, deadline, 10, false);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n            if ((int)pool.size() < 16) pool.push_back(seq);\n        }\n    }\n\n    // One last polish\n    if (Clock::now() < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = localDescent(seq, deadline, 25, true);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    cout << seqToString(bestSeq) << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int P = N * N;\nstatic constexpr int V = P * 4;\n\nstatic constexpr int DIR_L = 0;\nstatic constexpr int DIR_U = 1;\nstatic constexpr int DIR_R = 2;\nstatic constexpr int DIR_D = 3;\n\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int MATCH_REWARD = 2;\nstatic constexpr int BROKEN_PENALTY = -3;\nstatic constexpr int BOUNDARY_PENALTY = -3;\n\nstatic constexpr long long SCORE_FACTOR = 10000000000LL;\nstatic constexpr long long L2_FACTOR = 1000000LL;\nstatic constexpr long long L1_FACTOR = 100LL;\n\nusing StateArray = array<uint8_t, P>;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 1) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstruct CycleEval {\n    int L1 = 0;\n    int L2 = 0;\n    int total = 0;\n    int numCycles = 0;\n    long long score = 0;\n    long long scalarNoG = LLONG_MIN / 4;\n};\n\nstruct Eval {\n    int g = 0;\n    CycleEval c;\n    long long scalar = LLONG_MIN / 4;\n};\n\nstruct Candidate {\n    StateArray st{};\n    Eval ev;\n};\n\nstatic const int TO[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\nstatic chrono::steady_clock::time_point g_start;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ntemplate <class T>\nvoid shuffle_vec(vector<T>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.next_int(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nuint8_t activeMask[8];\nuint8_t stateToRot[8][8];\nuint8_t allowedState[P][4];\nuint8_t allowedCnt[P];\nuint8_t baseTile[P];\nbool isDoublePos[P];\nint16_t neighborPos[P][4];\n\nvector<int> allPos;\nvector<int> nonDoublePos;\nvector<int> doublePos;\nvector<array<int, 4>> blocks2x2;\n\ninline long long make_scalar(const CycleEval& c, int g) {\n    return c.score * SCORE_FACTOR\n         + 1LL * c.L2 * L2_FACTOR\n         + 1LL * c.L1 * L1_FACTOR\n         + 2LL * c.total\n         + g;\n}\n\ninline Eval make_eval(int g, const CycleEval& c) {\n    Eval e;\n    e.g = g;\n    e.c = c;\n    e.scalar = make_scalar(c, g);\n    return e;\n}\n\ninline int rotate_state(int b, int r) {\n    if (b <= 3) return (b + r) & 3;\n    if (b <= 5) return 4 + ((b - 4 + r) & 1);\n    return 6 + ((b - 6 + r) & 1);\n}\n\nvoid init_tables() {\n    for (int s = 0; s < 8; s++) {\n        uint8_t mask = 0;\n        for (int d = 0; d < 4; d++) {\n            if (TO[s][d] != -1) mask |= uint8_t(1u << d);\n        }\n        activeMask[s] = mask;\n    }\n\n    for (int b = 0; b < 8; b++) {\n        for (int s = 0; s < 8; s++) stateToRot[b][s] = 255;\n        for (int r = 0; r < 4; r++) {\n            int s = rotate_state(b, r);\n            stateToRot[b][s] = min<int>(stateToRot[b][s], r);\n        }\n    }\n\n    allPos.reserve(P);\n    nonDoublePos.reserve(P);\n    doublePos.reserve(P);\n    blocks2x2.reserve((N - 1) * (N - 1));\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            neighborPos[p][DIR_L] = (j > 0 ? p - 1 : -1);\n            neighborPos[p][DIR_U] = (i > 0 ? p - N : -1);\n            neighborPos[p][DIR_R] = (j + 1 < N ? p + 1 : -1);\n            neighborPos[p][DIR_D] = (i + 1 < N ? p + N : -1);\n        }\n    }\n\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j + 1 < N; j++) {\n            blocks2x2.push_back({i * N + j, i * N + (j + 1), (i + 1) * N + j, (i + 1) * N + (j + 1)});\n        }\n    }\n}\n\ninline int localCellScore(int pos, uint8_t s, const StateArray& st) {\n    int sc = 0;\n    uint8_t mask = activeMask[s];\n    for (int d = 0; d < 4; d++) {\n        bool a = (mask >> d) & 1u;\n        int np = neighborPos[pos][d];\n        if (np == -1) {\n            if (a) sc += BOUNDARY_PENALTY;\n        } else {\n            bool b = (activeMask[st[np]] >> opp[d]) & 1u;\n            if (a && b) sc += MATCH_REWARD;\n            else if (a != b) sc += BROKEN_PENALTY;\n        }\n    }\n    return sc;\n}\n\nint calc_g(const StateArray& st) {\n    int g = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            uint8_t m = activeMask[st[p]];\n\n            if (j == 0 && (m & (1u << DIR_L))) g += BOUNDARY_PENALTY;\n            if (i == 0 && (m & (1u << DIR_U))) g += BOUNDARY_PENALTY;\n\n            if (j + 1 < N) {\n                bool a = (m >> DIR_R) & 1u;\n                bool b = (activeMask[st[p + 1]] >> DIR_L) & 1u;\n                if (a && b) g += MATCH_REWARD;\n                else if (a != b) g += BROKEN_PENALTY;\n            } else {\n                if (m & (1u << DIR_R)) g += BOUNDARY_PENALTY;\n            }\n\n            if (i + 1 < N) {\n                bool a = (m >> DIR_D) & 1u;\n                bool b = (activeMask[st[p + N]] >> DIR_U) & 1u;\n                if (a && b) g += MATCH_REWARD;\n                else if (a != b) g += BROKEN_PENALTY;\n            } else {\n                if (m & (1u << DIR_D)) g += BOUNDARY_PENALTY;\n            }\n        }\n    }\n    return g;\n}\n\nCycleEval evaluateCycles(const StateArray& st) {\n    CycleEval res;\n    static uint8_t vis[V];\n    static int stk[V];\n    memset(vis, 0, sizeof(vis));\n\n    int L1 = 0, L2 = 0, total = 0, numCycles = 0;\n\n    for (int p = 0; p < P; p++) {\n        uint8_t s = st[p];\n        uint8_t mask = activeMask[s];\n        int base = p << 2;\n\n        while (mask) {\n            int d = __builtin_ctz(mask);\n            mask &= mask - 1;\n            int v = base + d;\n            if (vis[v]) continue;\n\n            bool isCycle = true;\n            int vertices = 0;\n            int top = 0;\n            stk[top++] = v;\n            vis[v] = 1;\n\n            while (top) {\n                int u = stk[--top];\n                vertices++;\n\n                int pp = u >> 2;\n                int dd = u & 3;\n                uint8_t ss = st[pp];\n\n                int md = TO[ss][dd];\n                int u2 = (pp << 2) + md;\n                if (!vis[u2]) {\n                    vis[u2] = 1;\n                    stk[top++] = u2;\n                }\n\n                int np = neighborPos[pp][dd];\n                if (np != -1 && ((activeMask[st[np]] >> opp[dd]) & 1u)) {\n                    int u3 = (np << 2) + opp[dd];\n                    if (!vis[u3]) {\n                        vis[u3] = 1;\n                        stk[top++] = u3;\n                    }\n                } else {\n                    isCycle = false;\n                }\n            }\n\n            if (isCycle) {\n                int len = vertices / 2;\n                total += len;\n                numCycles++;\n                if (len > L1) {\n                    L2 = L1;\n                    L1 = len;\n                } else if (len > L2) {\n                    L2 = len;\n                }\n            }\n        }\n    }\n\n    res.L1 = L1;\n    res.L2 = L2;\n    res.total = total;\n    res.numCycles = numCycles;\n    res.score = (numCycles >= 2 ? 1LL * L1 * L2 : 0LL);\n    res.scalarNoG = res.score * SCORE_FACTOR\n                  + 1LL * res.L2 * L2_FACTOR\n                  + 1LL * res.L1 * L1_FACTOR\n                  + 2LL * res.total;\n    return res;\n}\n\nEval evaluateFull(const StateArray& st) {\n    int g = calc_g(st);\n    CycleEval c = evaluateCycles(st);\n    return make_eval(g, c);\n}\n\nvoid optimizeLocalG(StateArray& st, RNG& rng, int sweeps = 10) {\n    vector<int> order = nonDoublePos;\n    for (int sw = 0; sw < sweeps; sw++) {\n        shuffle_vec(order, rng);\n        bool changed = false;\n\n        for (int pos : order) {\n            uint8_t cur = st[pos];\n            int curScore = localCellScore(pos, cur, st);\n            int bestScore = curScore;\n            uint8_t bests[4];\n            int bc = 0;\n\n            for (int k = 0; k < allowedCnt[pos]; k++) {\n                uint8_t ns = allowedState[pos][k];\n                if (ns == cur) continue;\n                int sc = localCellScore(pos, ns, st);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bests[0] = ns;\n                    bc = 1;\n                } else if (sc == bestScore && sc > curScore) {\n                    bests[bc++] = ns;\n                }\n            }\n\n            if (bestScore > curScore) {\n                st[pos] = bests[rng.next_int(bc)];\n                changed = true;\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid addPool(vector<Candidate>& pool, const StateArray& st, int keep = 8) {\n    Candidate c;\n    c.st = st;\n    c.ev = evaluateFull(st);\n    pool.push_back(c);\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n    if ((int)pool.size() > keep) pool.resize(keep);\n}\n\nvoid applyDoublePattern(StateArray& st, int patId) {\n    for (int p : doublePos) {\n        int i = p / N, j = p % N;\n        uint8_t v = 4;\n        switch (patId) {\n            case 0: v = 4; break;\n            case 1: v = 5; break;\n            case 2: v = ((i + j) & 1) ? 4 : 5; break;\n            case 3: v = ((i + j) & 1) ? 5 : 4; break;\n            case 4: v = (i & 1) ? 4 : 5; break;\n            case 5: v = (i & 1) ? 5 : 4; break;\n            case 6: v = (j & 1) ? 4 : 5; break;\n            case 7: v = (j & 1) ? 5 : 4; break;\n            default: v = 4; break;\n        }\n        st[p] = v;\n    }\n}\n\nvoid applyDoubleRandomMode(StateArray& st, RNG& rng, int mode) {\n    if (mode == 0) {\n        for (int p : doublePos) st[p] = uint8_t(4 + rng.next_int(2));\n    } else if (mode == 1) {\n        uint8_t rowv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = rowv[p / N];\n    } else if (mode == 2) {\n        uint8_t colv[N];\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = colv[p % N];\n    } else {\n        uint8_t rowv[N], colv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(rng.next_int(2));\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(rng.next_int(2));\n        int phase = rng.next_int(2);\n        for (int p : doublePos) {\n            int i = p / N, j = p % N;\n            st[p] = uint8_t(4 + ((rowv[i] ^ colv[j] ^ phase) & 1));\n        }\n    }\n}\n\nvoid hillDoubleSingle(StateArray& st, Eval& ev, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = doublePos;\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t ns = (orig == 4 ? 5 : 4);\n            st[pos] = ns;\n\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > ev.scalar) {\n                ev.c = c2;\n                ev.scalar = sc2;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid blockDouble2x2Pass(StateArray& st, Eval& ev, RNG& rng, int passes, double deadline) {\n    vector<int> order(blocks2x2.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int bi = 0; bi < (int)order.size(); bi++) {\n            if ((bi & 31) == 0 && elapsed_sec() > deadline) break;\n            const auto& b = blocks2x2[order[bi]];\n            int ps[4], k = 0;\n            for (int t = 0; t < 4; t++) {\n                if (isDoublePos[b[t]]) ps[k++] = b[t];\n            }\n            if (k <= 1) continue;\n\n            uint8_t orig[4];\n            int origMask = 0;\n            for (int t = 0; t < k; t++) {\n                orig[t] = st[ps[t]];\n                if (orig[t] == 5) origMask |= (1 << t);\n            }\n\n            int bestMask = origMask;\n            CycleEval bestC = ev.c;\n            long long bestScalar = ev.scalar;\n\n            int lim = 1 << k;\n            for (int mask = 0; mask < lim; mask++) {\n                if (mask == origMask) continue;\n                for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestScalar) {\n                    bestScalar = sc2;\n                    bestC = c2;\n                    bestMask = mask;\n                }\n            }\n\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n            if (bestMask != origMask) {\n                ev.c = bestC;\n                ev.scalar = bestScalar;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid hillNonDoubleGuided(StateArray& st, Eval& ev, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = nonDoublePos;\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            int curLocal = localCellScore(pos, orig, st);\n\n            uint8_t cand[4];\n            int cc = 0;\n            for (int k = 0; k < allowedCnt[pos]; k++) {\n                uint8_t ns = allowedState[pos][k];\n                if (ns == orig) continue;\n                int sc = localCellScore(pos, ns, st);\n                if (sc >= curLocal) cand[cc++] = ns;\n            }\n            if (cc == 0) continue;\n\n            uint8_t bestState = orig;\n            Eval bestEv = ev;\n\n            for (int t = 0; t < cc; t++) {\n                st[pos] = cand[t];\n                Eval e2 = evaluateFull(st);\n                if (e2.scalar > bestEv.scalar) {\n                    bestEv = e2;\n                    bestState = cand[t];\n                }\n            }\n\n            st[pos] = bestState;\n            if (bestState != orig) {\n                ev = bestEv;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid randomBlockSearchAll(StateArray& st, Eval& ev, RNG& rng, int iterations, int prodLimit, double deadline) {\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int si = rng.next_int(N - 1);\n        int sj = rng.next_int(N - 1);\n        int pos[4] = {si * N + sj, si * N + sj + 1, (si + 1) * N + sj, (si + 1) * N + sj + 1};\n\n        int cnts[4];\n        uint8_t opts[4][4];\n        int prod = 1;\n        for (int t = 0; t < 4; t++) {\n            cnts[t] = allowedCnt[pos[t]];\n            prod *= cnts[t];\n            if (prod > prodLimit) break;\n            for (int k = 0; k < cnts[t]; k++) opts[t][k] = allowedState[pos[t]][k];\n        }\n        if (prod > prodLimit) continue;\n\n        uint8_t bestStates[4];\n        for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n        Eval bestEv = ev;\n\n        for (int code = 0; code < prod; code++) {\n            int x = code;\n            for (int t = 0; t < 4; t++) {\n                st[pos[t]] = opts[t][x % cnts[t]];\n                x /= cnts[t];\n            }\n            Eval e2 = evaluateFull(st);\n            if (e2.scalar > bestEv.scalar) {\n                bestEv = e2;\n                for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n            }\n        }\n\n        bool changed = false;\n        for (int t = 0; t < 4; t++) {\n            if (st[pos[t]] != bestStates[t]) changed = true;\n            st[pos[t]] = bestStates[t];\n        }\n        if (bestEv.scalar > ev.scalar) {\n            ev = bestEv;\n        } else if (!changed) {\n            // already restored\n        }\n    }\n}\n\nvoid randomDoubleRegionSearch(StateArray& st, Eval& ev, RNG& rng, int iterations, double deadline) {\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int h = 2 + rng.next_int(2); // 2..3\n        int w = 2 + rng.next_int(2); // 2..3\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        int ps[9];\n        int k = 0;\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) ps[k++] = p;\n            }\n        }\n        if (k <= 1 || k > 8) continue;\n\n        int origMask = 0;\n        for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n        int bestMask = origMask;\n        CycleEval bestC = ev.c;\n        long long bestScalar = ev.scalar;\n\n        int lim = 1 << k;\n        for (int mask = 0; mask < lim; mask++) {\n            if (mask == origMask) continue;\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > bestScalar) {\n                bestScalar = sc2;\n                bestC = c2;\n                bestMask = mask;\n            }\n        }\n\n        for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n        if (bestMask != origMask) {\n            ev.c = bestC;\n            ev.scalar = bestScalar;\n        }\n    }\n}\n\nvoid perturb(StateArray& st, RNG& rng, int strength) {\n    int mode = rng.next_int(100);\n\n    if (mode < 55 && !doublePos.empty()) {\n        int h = 2 + rng.next_int(3); // 2..4\n        int w = 2 + rng.next_int(3); // 2..4\n        h = min(h, N);\n        w = min(w, N);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) {\n                    if (rng.next_int(100) < 80) st[p] = (st[p] == 4 ? 5 : 4);\n                } else if (rng.next_int(100) < 20) {\n                    st[p] = allowedState[p][rng.next_int(allowedCnt[p])];\n                }\n            }\n        }\n    } else {\n        int moves = 3 + rng.next_int(4) + min(8, strength / 4);\n        for (int t = 0; t < moves; t++) {\n            int p = rng.next_int(P);\n            st[p] = allowedState[p][rng.next_int(allowedCnt[p])];\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n    init_tables();\n\n    uint64_t seed = 1469598103934665603ULL;\n    vector<string> S(N);\n    for (int i = 0; i < N; i++) {\n        cin >> S[i];\n        for (char c : S[i]) {\n            seed ^= uint64_t((unsigned char)c + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    RNG rng(seed);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            int b = S[i][j] - '0';\n            baseTile[p] = (uint8_t)b;\n            isDoublePos[p] = (b == 4 || b == 5);\n            allPos.push_back(p);\n            if (isDoublePos[p]) doublePos.push_back(p);\n            else nonDoublePos.push_back(p);\n\n            int cnt = 0;\n            for (int s = 0; s < 8; s++) {\n                if (stateToRot[b][s] != 255) {\n                    allowedState[p][cnt++] = (uint8_t)s;\n                }\n            }\n            allowedCnt[p] = (uint8_t)cnt;\n        }\n    }\n\n    const double deadline = 1.94;\n\n    vector<Candidate> pool;\n    int baseStarts = 10;\n\n    for (int it = 0; it < baseStarts; it++) {\n        if (elapsed_sec() > 0.28) break;\n\n        StateArray base{};\n        for (int p = 0; p < P; p++) {\n            if (isDoublePos[p]) base[p] = 4;\n            else base[p] = allowedState[p][rng.next_int(allowedCnt[p])];\n        }\n        optimizeLocalG(base, rng, 12);\n\n        for (int pat = 0; pat < 8; pat++) {\n            StateArray cand = base;\n            applyDoublePattern(cand, pat);\n            addPool(pool, cand, 8);\n        }\n        for (int mode = 0; mode < 4; mode++) {\n            StateArray cand = base;\n            applyDoubleRandomMode(cand, rng, mode);\n            addPool(pool, cand, 8);\n        }\n    }\n\n    if (pool.empty()) {\n        StateArray st{};\n        for (int p = 0; p < P; p++) st[p] = allowedState[p][0];\n        addPool(pool, st, 8);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    int refineCount = min<int>(4, pool.size());\n    for (int i = 0; i < refineCount; i++) {\n        if (elapsed_sec() > 0.90) break;\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n        blockDouble2x2Pass(pool[i].st, pool[i].ev, rng, 1, deadline);\n        hillNonDoubleGuided(pool[i].st, pool[i].ev, rng, 1, deadline);\n        randomBlockSearchAll(pool[i].st, pool[i].ev, rng, 30, 128, deadline);\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    Candidate best = pool[0];\n    Candidate current = best;\n    int stagnation = 0;\n\n    while (elapsed_sec() < deadline - 0.10) {\n        StateArray trial = (rng.next_int(100) < 60 ? current.st : best.st);\n        perturb(trial, rng, stagnation);\n        Eval tev = evaluateFull(trial);\n\n        randomDoubleRegionSearch(trial, tev, rng, 28, deadline);\n        hillDoubleSingle(trial, tev, rng, 1, deadline);\n        if (rng.next_int(100) < 70) {\n            randomBlockSearchAll(trial, tev, rng, 18, 96, deadline);\n        }\n        hillNonDoubleGuided(trial, tev, rng, 1, deadline);\n        if (rng.next_int(100) < 45) {\n            randomDoubleRegionSearch(trial, tev, rng, 16, deadline);\n        }\n\n        if (tev.scalar > best.ev.scalar) {\n            best.st = trial;\n            best.ev = tev;\n            current = best;\n            stagnation = 0;\n            pool.push_back(best);\n            sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n                return a.ev.scalar > b.ev.scalar;\n            });\n            if ((int)pool.size() > 8) pool.resize(8);\n        } else {\n            stagnation++;\n        }\n\n        if (tev.scalar > current.ev.scalar || rng.next_int(100) < (stagnation < 10 ? 18 : 30)) {\n            current.st = trial;\n            current.ev = tev;\n        }\n\n        if (stagnation >= 18 && !pool.empty()) {\n            current = pool[rng.next_int((int)pool.size())];\n            stagnation = 0;\n        }\n    }\n\n    // Final polish\n    hillDoubleSingle(best.st, best.ev, rng, 2, deadline);\n    blockDouble2x2Pass(best.st, best.ev, rng, 2, deadline);\n    randomBlockSearchAll(best.st, best.ev, rng, 50, 128, deadline);\n    hillNonDoubleGuided(best.st, best.ev, rng, 3, deadline);\n    hillDoubleSingle(best.st, best.ev, rng, 2, deadline);\n    blockDouble2x2Pass(best.st, best.ev, rng, 1, deadline);\n\n    string ans;\n    ans.resize(P);\n    for (int p = 0; p < P; p++) {\n        uint8_t r = stateToRot[baseTile[p]][best.st[p]];\n        if (r == 255) r = 0;\n        ans[p] = char('0' + r);\n    }\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nstatic constexpr int MAXC = 100;\nstatic constexpr uint16_t NIL = 65535;\n\nstruct FastHash {\n    static ull splitmix64(ull 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()(ull x) const {\n        static const ull FIXED_RANDOM =\n            chrono::steady_clock::now().time_since_epoch().count();\n        return (size_t)splitmix64(x + FIXED_RANDOM);\n    }\n};\n\nstruct Metrics {\n    int tree = 1;\n    int largest_comp = 1;\n    int matched = 0;\n    int components = 1;\n    int cycle_excess = 0;\n    int full_tiles = 0;\n    int sumsq = 1;\n    int pot_max = 1;\n    int pot_sum = 1;\n    int hole_bad = 0;\n    int dist = 0;\n};\n\nstruct Node {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1; // 0:U 1:D 2:L 3:R\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct Cand {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1;\n    uint16_t parent = NIL;\n    char mv = '?';\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct SearchResult {\n    string best_tree_path;\n    int best_tree = 1;\n    string best_mode_path;\n    long long best_mode_score = LLONG_MIN;\n};\n\nstruct Solver {\n    int N, T, NN, FULL;\n    array<int, MAXC> nxtU, nxtD, nxtL, nxtR;\n    array<array<int, MAXC>, 4> nxtPos{};\n    array<int, MAXC> rr{}, cc{};\n    array<array<ull, 16>, MAXC> zob{};\n    ull lastSalt[5]{};\n    int popc[16]{};\n\n    chrono::steady_clock::time_point st;\n    double total_limit_sec = 2.82;\n\n    static ull splitmix64_ref(ull &x) {\n        ull z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool time_over(double deadline) const {\n        return elapsed() >= deadline;\n    }\n\n    static int hexval(char c) {\n        if ('0' <= c && c <= '9') return c - '0';\n        return c - 'a' + 10;\n    }\n\n    static int char_to_dir(char c) {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        return 3; // R\n    }\n\n    ull state_key(ull h, int last) const {\n        return h ^ lastSalt[last + 1];\n    }\n\n    string build_path(int depth, int idx,\n                      const vector<vector<uint16_t>> &parents,\n                      const vector<vector<char>> &moves) const {\n        string res(depth, '?');\n        while (depth > 0) {\n            res[depth - 1] = moves[depth][idx];\n            idx = parents[depth][idx];\n            --depth;\n        }\n        return res;\n    }\n\n    Metrics evaluate(const array<unsigned char, MAXC> &b, int blank) const {\n        int parent[MAXC];\n        int sz[MAXC];\n        int ed[MAXC];\n        unsigned char mdeg[MAXC];\n\n        for (int i = 0; i < NN; i++) {\n            mdeg[i] = 0;\n            if (b[i] == 0) {\n                parent[i] = -1;\n                sz[i] = 0;\n                ed[i] = 0;\n            } else {\n                parent[i] = i;\n                sz[i] = 1;\n                ed[i] = 0;\n            }\n        }\n\n        auto find = [&](int x) {\n            while (parent[x] != x) {\n                parent[x] = parent[parent[x]];\n                x = parent[x];\n            }\n            return x;\n        };\n\n        auto unite_edge = [&](int a, int c) {\n            int ra = find(a), rb = find(c);\n            if (ra == rb) {\n                ed[ra]++;\n            } else {\n                if (sz[ra] < sz[rb]) swap(ra, rb);\n                parent[rb] = ra;\n                sz[ra] += sz[rb];\n                ed[ra] += ed[rb] + 1;\n            }\n        };\n\n        Metrics m;\n        m.tree = 1;\n        m.largest_comp = 1;\n        m.matched = 0;\n        m.components = 0;\n        m.cycle_excess = 0;\n        m.full_tiles = 0;\n        m.sumsq = 0;\n        m.pot_max = 1;\n        m.pot_sum = 0;\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n\n            int r = nxtR[i];\n            if (r != -1) {\n                unsigned char tr = b[r];\n                if ((t & 4) && (tr & 1)) {\n                    unite_edge(i, r);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[r]++;\n                }\n            }\n\n            int d = nxtD[i];\n            if (d != -1) {\n                unsigned char td = b[d];\n                if ((t & 8) && (td & 2)) {\n                    unite_edge(i, d);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[d]++;\n                }\n            }\n        }\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n            if ((int)mdeg[i] == popc[t]) m.full_tiles++;\n        }\n\n        for (int i = 0; i < NN; i++) {\n            if (parent[i] == i) {\n                m.components++;\n                int v = sz[i];\n                int ex = ed[i] - v + 1;\n                if (ex < 0) ex = 0;\n                m.cycle_excess += ex;\n                m.largest_comp = max(m.largest_comp, v);\n                if (ed[i] == v - 1) m.tree = max(m.tree, v);\n                m.sumsq += v * v;\n                int pot = v - 2 * ex;\n                if (pot < 0) pot = 0;\n                m.pot_max = max(m.pot_max, pot);\n                m.pot_sum += pot;\n            }\n        }\n\n        // hole conflicts: stubs pointing into the blank\n        m.hole_bad = 0;\n        int u = nxtU[blank], d = nxtD[blank], l = nxtL[blank], r = nxtR[blank];\n        if (u != -1 && (b[u] & 8)) m.hole_bad++;\n        if (d != -1 && (b[d] & 2)) m.hole_bad++;\n        if (l != -1 && (b[l] & 4)) m.hole_bad++;\n        if (r != -1 && (b[r] & 1)) m.hole_bad++;\n\n        m.dist = (N - 1 - rr[blank]) + (N - 1 - cc[blank]);\n\n        return m;\n    }\n\n    long long score_of(const Metrics &m, int mode) const {\n        if (mode == 0) {\n            // Global completion-oriented:\n            // fewer cycles/components via matched-3*cycles,\n            // more fully satisfied tiles, bigger merged regions.\n            return\n                1'000'000'000'000LL * (m.matched - 3 * m.cycle_excess) +\n                1'000'000'000LL * m.full_tiles +\n                100'000LL * m.sumsq +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        } else if (mode == 1) {\n            // Large near-tree component.\n            return\n                1'000'000'000'000LL * m.pot_max +\n                1'000'000'000LL * m.tree +\n                1'000'000LL * (m.matched - 2 * m.cycle_excess) +\n                1'000LL * m.full_tiles +\n                m.largest_comp -\n                10LL * m.hole_bad;\n        } else {\n            // Local consistency.\n            return\n                1'000'000'000'000LL * m.full_tiles +\n                1'000'000'000LL * m.matched +\n                1'000'000LL * m.pot_sum +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        }\n    }\n\n    SearchResult beam_search(const array<unsigned char, MAXC> &start_board,\n                             int start_blank,\n                             int depth_limit,\n                             int mode,\n                             int width,\n                             double deadline,\n                             int start_last = -1,\n                             ull tie_salt = 0) {\n        SearchResult res;\n\n        Node root;\n        root.b = start_board;\n        root.blank = start_blank;\n        root.last = (signed char)start_last;\n        root.h = 0;\n        for (int i = 0; i < NN; i++) root.h ^= zob[i][root.b[i]];\n\n        Metrics rm = evaluate(root.b, root.blank);\n        root.tree = (short)rm.tree;\n        root.score = score_of(rm, mode);\n\n        res.best_tree = root.tree;\n        res.best_tree_path = \"\";\n        res.best_mode_score = root.score;\n        res.best_mode_path = \"\";\n\n        if (root.tree == FULL || depth_limit == 0) return res;\n\n        vector<Node> cur, next;\n        cur.reserve(width);\n        next.reserve(width);\n        cur.push_back(root);\n\n        vector<vector<uint16_t>> parents(depth_limit + 1);\n        vector<vector<char>> moves(depth_limit + 1);\n        parents[0].push_back(NIL);\n        moves[0].push_back('?');\n\n        unordered_set<ull, FastHash> seen;\n        {\n            size_t est = (size_t)min<long long>((long long)width * min(depth_limit, 1500) + 1024LL, 2'000'000LL);\n            seen.reserve(est * 2 + 1);\n            seen.max_load_factor(0.7f);\n        }\n        seen.insert(state_key(root.h, root.last));\n\n        const int inv[4] = {1, 0, 3, 2};\n        const char dirc[4] = {'U', 'D', 'L', 'R'};\n\n        vector<Cand> cands;\n        cands.reserve(width * 3 + 8);\n\n        int blankCap = (N <= 7 ? 12 : 8);\n        int blankLastCap = 3;\n\n        for (int depth = 0; depth < depth_limit; depth++) {\n            if (time_over(deadline)) break;\n\n            cands.clear();\n\n            for (int pi = 0; pi < (int)cur.size(); pi++) {\n                if ((pi & 31) == 0 && time_over(deadline)) break;\n                const Node &nd = cur[pi];\n\n                for (int dir = 0; dir < 4; dir++) {\n                    if (nd.last != -1 && inv[dir] == nd.last) continue;\n                    int nb = nxtPos[dir][nd.blank];\n                    if (nb == -1) continue;\n\n                    unsigned char tile = nd.b[nb];\n                    ull nh = nd.h ^ zob[nd.blank][0] ^ zob[nb][tile] ^ zob[nd.blank][tile] ^ zob[nb][0];\n                    ull key = state_key(nh, dir);\n                    if (seen.find(key) != seen.end()) continue;\n\n                    Cand cd;\n                    cd.b = nd.b;\n                    cd.b[nd.blank] = tile;\n                    cd.b[nb] = 0;\n                    cd.h = nh;\n                    cd.blank = nb;\n                    cd.last = (signed char)dir;\n                    cd.parent = (uint16_t)pi;\n                    cd.mv = dirc[dir];\n\n                    Metrics m = evaluate(cd.b, cd.blank);\n                    cd.tree = (short)m.tree;\n                    cd.score = score_of(m, mode);\n\n                    cands.push_back(std::move(cd));\n\n                    if (m.tree > res.best_tree) {\n                        res.best_tree = m.tree;\n                        res.best_tree_path = build_path(depth, pi, parents, moves);\n                        res.best_tree_path.push_back(dirc[dir]);\n                        if (m.tree == FULL) return res;\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand &a, const Cand &b) {\n                if (a.score != b.score) return a.score > b.score;\n                return (a.h ^ tie_salt) < (b.h ^ tie_salt);\n            });\n\n            unordered_set<ull, FastHash> used;\n            used.reserve(cands.size() * 2 + 1);\n            used.max_load_factor(0.7f);\n\n            vector<unsigned char> blankCnt(NN, 0);\n            vector<array<unsigned char, 4>> blankLastCnt(NN);\n            for (int i = 0; i < NN; i++) blankLastCnt[i] = {0, 0, 0, 0};\n\n            next.clear();\n            parents[depth + 1].clear();\n            moves[depth + 1].clear();\n            next.reserve(width);\n            parents[depth + 1].reserve(width);\n            moves[depth + 1].reserve(width);\n\n            auto try_add = [&](const Cand &cd, bool use_cap) -> bool {\n                ull key = state_key(cd.h, cd.last);\n                if (used.find(key) != used.end()) return false;\n                if (seen.find(key) != seen.end()) return false;\n\n                if (use_cap) {\n                    if (blankCnt[cd.blank] >= blankCap) return false;\n                    if (blankLastCnt[cd.blank][cd.last] >= blankLastCap) return false;\n                }\n\n                used.insert(key);\n                seen.insert(key);\n                blankCnt[cd.blank]++;\n                blankLastCnt[cd.blank][cd.last]++;\n\n                Node nd;\n                nd.b = cd.b;\n                nd.h = cd.h;\n                nd.blank = cd.blank;\n                nd.last = cd.last;\n                nd.tree = cd.tree;\n                nd.score = cd.score;\n                next.push_back(std::move(nd));\n                parents[depth + 1].push_back(cd.parent);\n                moves[depth + 1].push_back(cd.mv);\n\n                if (cd.score > res.best_mode_score) {\n                    res.best_mode_score = cd.score;\n                    res.best_mode_path = build_path(depth + 1, (int)next.size() - 1, parents, moves);\n                }\n                return true;\n            };\n\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, true);\n            }\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, false);\n            }\n\n            if (next.empty()) break;\n            cur.swap(next);\n        }\n\n        return res;\n    }\n\n    void apply_moves(array<unsigned char, MAXC> &b, int &blank, const string &path) const {\n        for (char c : path) {\n            int dir = char_to_dir(c);\n            int nb = nxtPos[dir][blank];\n            unsigned char tile = b[nb];\n            b[blank] = tile;\n            b[nb] = 0;\n            blank = nb;\n        }\n    }\n\n    bool better_solution(int treeA, int lenA, int treeB, int lenB) const {\n        if (treeA != treeB) return treeA > treeB;\n        if (treeA == FULL && treeB == FULL) return lenA < lenB;\n        return false;\n    }\n\n    int base_width() const {\n        if (N <= 6) return 2200;\n        if (N == 7) return 1600;\n        if (N == 8) return 950;\n        if (N == 9) return 650;\n        return 450;\n    }\n\n    void solve() {\n        cin >> N >> T;\n        NN = N * N;\n        FULL = NN - 1;\n\n        array<unsigned char, MAXC> init_board{};\n        int init_blank = -1;\n        for (int i = 0; i < N; i++) {\n            string s;\n            cin >> s;\n            for (int j = 0; j < N; j++) {\n                int v = hexval(s[j]);\n                init_board[i * N + j] = (unsigned char)v;\n                if (v == 0) init_blank = i * N + j;\n            }\n        }\n\n        for (int i = 0; i < 16; i++) popc[i] = __builtin_popcount(i);\n\n        for (int i = 0; i < NN; i++) {\n            int r = i / N, c = i % N;\n            rr[i] = r;\n            cc[i] = c;\n            nxtU[i] = (r > 0 ? i - N : -1);\n            nxtD[i] = (r + 1 < N ? i + N : -1);\n            nxtL[i] = (c > 0 ? i - 1 : -1);\n            nxtR[i] = (c + 1 < N ? i + 1 : -1);\n            nxtPos[0][i] = nxtU[i];\n            nxtPos[1][i] = nxtD[i];\n            nxtPos[2][i] = nxtL[i];\n            nxtPos[3][i] = nxtR[i];\n        }\n\n        ull seed = 0x123456789abcdef0ULL;\n        for (int i = 0; i < NN; i++) {\n            for (int v = 0; v < 16; v++) zob[i][v] = splitmix64_ref(seed);\n        }\n        for (int i = 0; i < 5; i++) lastSalt[i] = splitmix64_ref(seed);\n\n        st = chrono::steady_clock::now();\n\n        Metrics initM = evaluate(init_board, init_blank);\n        string best_path = \"\";\n        int best_tree = initM.tree;\n\n        int W = base_width();\n\n        double d1 = total_limit_sec * 0.40;\n        double d2 = total_limit_sec * 0.72;\n        double d3 = total_limit_sec * 0.90;\n        double d4 = total_limit_sec - 0.02;\n\n        ull salt1 = splitmix64_ref(seed);\n        ull salt2 = splitmix64_ref(seed);\n        ull salt3 = splitmix64_ref(seed);\n        ull salt4 = splitmix64_ref(seed);\n\n        SearchResult r0, r1;\n\n        // Run 1: global-completion beam\n        if (!time_over(d1)) {\n            r0 = beam_search(init_board, init_blank, T, 0, W, d1, -1, salt1);\n            if (better_solution(r0.best_tree, (int)r0.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r0.best_tree;\n                best_path = r0.best_tree_path;\n            }\n        }\n\n        // Run 2: big-near-tree beam\n        if (!time_over(d2)) {\n            r1 = beam_search(init_board, init_blank, T, 1, (W * 3) / 4, d2, -1, salt2);\n            if (better_solution(r1.best_tree, (int)r1.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r1.best_tree;\n                best_path = r1.best_tree_path;\n            }\n        }\n\n        // Choose a promising intermediate path for refinement.\n        vector<string> candidates;\n        candidates.push_back(best_path);\n        candidates.push_back(r0.best_mode_path);\n        candidates.push_back(r1.best_mode_path);\n        candidates.push_back(r0.best_tree_path);\n        candidates.push_back(r1.best_tree_path);\n\n        sort(candidates.begin(), candidates.end());\n        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());\n\n        string refine_start = best_path;\n        long long refine_best_score = LLONG_MIN;\n        int refine_best_len = (int)best_path.size();\n\n        for (const string &p : candidates) {\n            if ((int)p.size() > T) continue;\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, p);\n            Metrics m = evaluate(b, blank);\n            long long sc = score_of(m, 0); // completion-oriented\n            if (sc > refine_best_score || (sc == refine_best_score && (int)p.size() < refine_best_len)) {\n                refine_best_score = sc;\n                refine_best_len = (int)p.size();\n                refine_start = p;\n            }\n        }\n\n        // Refinement 1 from the most completion-promising state.\n        if (!time_over(d3) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, refine_start);\n            int rem = T - (int)refine_start.size();\n            int stlast = refine_start.empty() ? -1 : char_to_dir(refine_start.back());\n            if (rem > 0) {\n                auto rr0 = beam_search(b, blank, rem, 0, (W * 2) / 3, d3, stlast, salt3);\n                string cand_path = refine_start + rr0.best_tree_path;\n                if (better_solution(rr0.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr0.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        // Refinement 2 from current best tree state, slightly different heuristic.\n        if (!time_over(d4) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, best_path);\n            int rem = T - (int)best_path.size();\n            int stlast = best_path.empty() ? -1 : char_to_dir(best_path.back());\n            if (rem > 0) {\n                auto rr1 = beam_search(b, blank, rem, 1, max(120, W / 2), d4, stlast, salt4);\n                string cand_path = best_path + rr1.best_tree_path;\n                if (better_solution(rr1.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr1.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        cout << best_path << '\\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}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int R = 10000;\nstatic constexpr int MAX_CUTS = 100;\nstatic constexpr int NORMAL_MAX = 4096;\nstatic constexpr int MIN_NORM = 1000;\nstatic constexpr long double SQRT3 = 1.7320508075688772935L;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Line {\n    int A, B; // primitive, sign-normalized\n    ll C;     // Ax + By = C\n};\n\nstruct State {\n    vector<int> cell;      // cell id per point\n    vector<int> cellSize;  // size of each cell\n    array<int, 11> hist{}; // hist[d] = number of cells with d strawberries\n    int rawScore = 0;\n    int smallCount = 0;    // sum hist[1..10]\n};\n\nstruct Cand2 {\n    int A, B; // primitive, sign-normalized\n    int t1, t2;\n    double alpha1, alpha2;\n    double off1, off2;\n};\n\nstruct Cand3 {\n    array<pair<int,int>,3> n;\n    int t[3];\n    double alpha[3];\n    double off[3];\n};\n\nstruct BestLineRes {\n    bool ok = false;\n    int raw = -1e9;\n    int small = -1e9;\n    Line line{};\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double uniform() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    double uniform(double l, double r) {\n        return l + (r - l) * uniform();\n    }\n    ll next_ll(ll l, ll r) {\n        if (l > r) swap(l, r);\n        unsigned long long w = (unsigned long long)(r - l + 1);\n        return l + (ll)(next() % w);\n    }\n    int next_int(int l, int r) {\n        return (int)next_ll(l, r);\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\nint N, K;\nint a_need[11];\nint attendees_sum = 0;\nvector<Pt> pts;\nXorShift64 rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n\ntemplate <class T>\nT clampv(T x, T l, T r) {\n    return min(r, max(l, x));\n}\n\nstatic inline ll proj(int A, int B, const Pt& p) {\n    return 1LL * A * p.x + 1LL * B * p.y;\n}\n\nstatic inline ll norm2(pair<int,int> p) {\n    return 1LL * p.first * p.first + 1LL * p.second * p.second;\n}\n\npair<int,int> normalize_pair(ll A, ll B) {\n    if (A == 0 && B == 0) return {0, 0};\n    ll g = std::gcd(std::llabs(A), std::llabs(B));\n    A /= g;\n    B /= g;\n    if (A < 0 || (A == 0 && B < 0)) {\n        A = -A;\n        B = -B;\n    }\n    return {(int)A, (int)B};\n}\n\nLine normalize_line(Line ln) {\n    auto p = normalize_pair(ln.A, ln.B);\n    if (p.first != ln.A || p.second != ln.B) {\n        ll g = std::gcd(std::llabs((ll)ln.A), std::llabs((ll)ln.B));\n        ln.A = p.first;\n        ln.B = p.second;\n        ln.C /= g;\n    }\n    if (ln.A < 0 || (ln.A == 0 && ln.B < 0)) {\n        ln.A = -ln.A;\n        ln.B = -ln.B;\n        ln.C = -ln.C;\n    }\n    return ln;\n}\n\npair<int,int> random_primitive_large() {\n    while (true) {\n        ll A = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        ll B = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        if (A == 0 && B == 0) continue;\n        auto p = normalize_pair(A, B);\n        if (norm2(p) < 1LL * MIN_NORM * MIN_NORM) continue;\n        return p;\n    }\n}\n\npair<int,int> rotate60(pair<int,int> p) {\n    long double x = 0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first + 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\npair<int,int> rotate120(pair<int,int> p) {\n    long double x = -0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first - 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\nint compute_raw_from_hist(const array<int,11>& hist) {\n    int raw = 0;\n    for (int d = 1; d <= 10; d++) raw += min(a_need[d], hist[d]);\n    return raw;\n}\n\nvoid recompute_score(State& st) {\n    st.hist.fill(0);\n    for (int s : st.cellSize) {\n        if (1 <= s && s <= 10) st.hist[s]++;\n    }\n    st.smallCount = 0;\n    for (int d = 1; d <= 10; d++) st.smallCount += st.hist[d];\n    st.rawScore = compute_raw_from_hist(st.hist);\n}\n\nint index_from_proj(ll u, ll start, ll step, int t) {\n    ll d = u - start;\n    if (d < 0) return 0;\n    ll q = d / step;\n    if (q >= t) return t;\n    if (d % step == 0) return -1; // on line\n    return (int)q + 1;\n}\n\nint raw_from_counts(const vector<int>& cnt) {\n    array<int,11> hist{};\n    for (int c : cnt) {\n        if (1 <= c && c <= 10) hist[c]++;\n    }\n    return compute_raw_from_hist(hist);\n}\n\nint eval_cand2(const Cand2& c) {\n    static vector<int> cnt;\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    int A1 = c.A, B1 = c.B;\n    auto n2 = normalize_pair(-c.B, c.A);\n    int A2 = n2.first, B2 = n2.second;\n\n    int W = c.t2 + 1;\n    int SZ = (c.t1 + 1) * (c.t2 + 1);\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int i = index_from_proj(proj(A1, B1, p), start1, step1, c.t1);\n        if (i < 0) continue;\n        int j = index_from_proj(proj(A2, B2, p), start2, step2, c.t2);\n        if (j < 0) continue;\n        cnt[i * W + j]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nint eval_cand3(const Cand3& c) {\n    static vector<int> cnt;\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    int W1 = c.t[1] + 1;\n    int W2 = c.t[2] + 1;\n    int SZ = (c.t[0] + 1) * W1 * W2;\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int idx[3];\n        bool bad = false;\n        for (int k = 0; k < 3; k++) {\n            idx[k] = index_from_proj(proj(c.n[k].first, c.n[k].second, p), start[k], step[k], c.t[k]);\n            if (idx[k] < 0) {\n                bad = true;\n                break;\n            }\n        }\n        if (bad) continue;\n        int id = (idx[0] * W1 + idx[1]) * W2 + idx[2];\n        cnt[id]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nbool point_on_line(const Line& ln, const Pt& p) {\n    return proj(ln.A, ln.B, p) == ln.C;\n}\n\nbool has_collision_line(int A, int B, ll C) {\n    for (const auto& p : pts) if (proj(A, B, p) == C) return true;\n    return false;\n}\n\nll find_valid_C_near(int A, int B, ll base, unordered_set<ll>& used) {\n    auto bad = [&](ll C)->bool {\n        if (used.find(C) != used.end()) return true;\n        return has_collision_line(A, B, C);\n    };\n    if (!bad(base)) return base;\n    for (ll d = 1;; d++) {\n        if (!bad(base + d)) return base + d;\n        if (!bad(base - d)) return base - d;\n    }\n}\n\nvector<Line> build_lines2(const Cand2& c, vector<pair<int,int>>& normals_out) {\n    normals_out.clear();\n    auto n1 = normalize_pair(c.A, c.B);\n    auto n2 = normalize_pair(-c.B, c.A);\n    normals_out.push_back(n1);\n    normals_out.push_back(n2);\n\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    vector<Line> res;\n    res.reserve(c.t1 + c.t2);\n\n    unordered_set<ll> used1, used2;\n    used1.reserve(c.t1 * 2 + 3);\n    used2.reserve(c.t2 * 2 + 3);\n\n    for (int j = 0; j < c.t1; j++) {\n        ll C = start1 + 1LL * j * step1;\n        C = find_valid_C_near(n1.first, n1.second, C, used1);\n        used1.insert(C);\n        res.push_back(Line{n1.first, n1.second, C});\n    }\n    for (int j = 0; j < c.t2; j++) {\n        ll C = start2 + 1LL * j * step2;\n        C = find_valid_C_near(n2.first, n2.second, C, used2);\n        used2.insert(C);\n        res.push_back(Line{n2.first, n2.second, C});\n    }\n    return res;\n}\n\nvector<Line> build_lines3(const Cand3& c, vector<pair<int,int>>& normals_out) {\n    normals_out.clear();\n    for (int k = 0; k < 3; k++) normals_out.push_back(normalize_pair(c.n[k].first, c.n[k].second));\n\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    vector<Line> res;\n    res.reserve(c.t[0] + c.t[1] + c.t[2]);\n\n    unordered_set<ll> used[3];\n    for (int k = 0; k < 3; k++) used[k].reserve(c.t[k] * 2 + 3);\n\n    for (int k = 0; k < 3; k++) {\n        auto n = normalize_pair(c.n[k].first, c.n[k].second);\n        for (int j = 0; j < c.t[k]; j++) {\n            ll C = start[k] + 1LL * j * step[k];\n            C = find_valid_C_near(n.first, n.second, C, used[k]);\n            used[k].insert(C);\n            res.push_back(Line{n.first, n.second, C});\n        }\n    }\n    return res;\n}\n\nvoid apply_line(State& st, const Line& ln) {\n    int M = (int)st.cellSize.size();\n\n    static vector<int> pos, neg, newPosId, newNegId;\n    static vector<unsigned char> side;\n\n    pos.assign(M, 0);\n    neg.assign(M, 0);\n    side.assign(N, 0);\n\n    for (int i = 0; i < N; i++) {\n        ll v = proj(ln.A, ln.B, pts[i]) - ln.C;\n        int id = st.cell[i];\n        if (v > 0) {\n            side[i] = 1;\n            pos[id]++;\n        } else {\n            side[i] = 0;\n            neg[id]++;\n        }\n    }\n\n    newPosId.assign(M, -1);\n    newNegId.assign(M, -1);\n    vector<int> newSizes;\n    newSizes.reserve(min(N, 2 * M));\n\n    for (int id = 0; id < M; id++) {\n        if (neg[id] > 0) {\n            newNegId[id] = (int)newSizes.size();\n            newSizes.push_back(neg[id]);\n        }\n        if (pos[id] > 0) {\n            newPosId[id] = (int)newSizes.size();\n            newSizes.push_back(pos[id]);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        int old = st.cell[i];\n        st.cell[i] = side[i] ? newPosId[old] : newNegId[old];\n    }\n    st.cellSize.swap(newSizes);\n    recompute_score(st);\n}\n\nState build_state_excluding(const vector<Line>& lines, int skip = -1) {\n    State st;\n    st.cell.assign(N, 0);\n    st.cellSize = {N};\n    recompute_score(st);\n    for (int i = 0; i < (int)lines.size(); i++) {\n        if (i == skip) continue;\n        apply_line(st, lines[i]);\n    }\n    return st;\n}\n\nState build_state(const vector<Line>& lines) {\n    return build_state_excluding(lines, -1);\n}\n\nbool better_init(int raw, int numLines, int bestRaw, int bestLines) {\n    return (raw > bestRaw) || (raw == bestRaw && numLines < bestLines);\n}\n\ndouble estimate_lambda_star() {\n    double bestLam = max(1.0, (double)N / attendees_sum);\n    double bestVal = -1e100;\n    for (double lam = 0.8; lam <= 10.0; lam += 0.02) {\n        double C = N / lam;\n        double p = exp(-lam);\n        double cur = 0.0;\n        double pk = p;\n        for (int d = 1; d <= 10; d++) {\n            pk *= lam / d;\n            cur += min<double>(a_need[d], C * pk);\n        }\n        if (cur > bestVal) {\n            bestVal = cur;\n            bestLam = lam;\n        }\n    }\n    return bestLam;\n}\n\nCand2 random_cand2(double lambdaCenter) {\n    Cand2 c;\n    auto n = random_primitive_large();\n    c.A = n.first;\n    c.B = n.second;\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.85, 0.85)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double aspect = exp(rng.uniform(-0.8, 0.8));\n    double prod = 4.0 * Ctarget / acos(-1.0);\n\n    c.t1 = max(1, (int)llround(sqrt(prod * aspect) - 1.0));\n    c.t2 = max(1, (int)llround(sqrt(prod / aspect) - 1.0));\n\n    int sum = c.t1 + c.t2;\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        c.t1 = max(1, (int)floor(c.t1 * sc));\n        c.t2 = max(1, (int)floor(c.t2 * sc));\n        while (c.t1 + c.t2 > MAX_CUTS) {\n            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n            else if (c.t2 > 1) c.t2--;\n            else break;\n        }\n    }\n\n    c.alpha1 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.alpha2 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.off1 = rng.uniform(-0.5, 0.5);\n    c.off2 = rng.uniform(-0.5, 0.5);\n    return c;\n}\n\nCand3 random_cand3(double lambdaCenter) {\n    Cand3 c;\n    while (true) {\n        auto n0 = random_primitive_large();\n        auto n1 = rotate60(n0);\n        auto n2 = rotate120(n0);\n        if ((n1.first || n1.second) && (n2.first || n2.second)\n            && norm2(n1) >= 250000 && norm2(n2) >= 250000) {\n            c.n[0] = n0;\n            c.n[1] = n1;\n            c.n[2] = n2;\n            break;\n        }\n    }\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.8, 0.8)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double base = sqrt(max(1.0, Ctarget / 3.0));\n\n    for (int k = 0; k < 3; k++) {\n        c.t[k] = max(1, (int)llround(base * exp(rng.uniform(-0.45, 0.45))));\n    }\n\n    int sum = c.t[0] + c.t[1] + c.t[2];\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        for (int k = 0; k < 3; k++) c.t[k] = max(1, (int)floor(c.t[k] * sc));\n        while (c.t[0] + c.t[1] + c.t[2] > MAX_CUTS) {\n            int id = 0;\n            if (c.t[1] > c.t[id]) id = 1;\n            if (c.t[2] > c.t[id]) id = 2;\n            if (c.t[id] > 1) c.t[id]--;\n            else break;\n        }\n    }\n\n    for (int k = 0; k < 3; k++) {\n        c.alpha[k] = clampv(exp(rng.uniform(-0.35, 0.35)), 0.55, 1.6);\n        c.off[k] = rng.uniform(-0.5, 0.5);\n    }\n    return c;\n}\n\nvector<pair<int,int>> unique_normals(const vector<Line>& lines) {\n    set<pair<int,int>> s;\n    for (const auto& ln : lines) s.insert(normalize_pair(ln.A, ln.B));\n    return vector<pair<int,int>>(s.begin(), s.end());\n}\n\npair<int,int> combine_normals(pair<int,int> a, pair<int,int> b, int sign) {\n    ll A = (ll)a.first + sign * (ll)b.first;\n    ll B = (ll)a.second + sign * (ll)b.second;\n    auto p = normalize_pair(A, B);\n    if (p.first == 0 && p.second == 0) return random_primitive_large();\n    return p;\n}\n\nuint64_t norm_key(pair<int,int> p) {\n    uint64_t a = (uint32_t)(p.first + 1000000000);\n    uint64_t b = (uint32_t)(p.second + 1000000000);\n    return (a << 32) ^ b;\n}\n\nvoid add_normal(vector<pair<int,int>>& out, unordered_set<uint64_t>& seen, pair<int,int> n) {\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return;\n    uint64_t key = norm_key(n);\n    if (seen.insert(key).second) out.push_back(n);\n}\n\nint pick_biased_point(const State& st) {\n    int best = rng.next_int(0, N - 1);\n    for (int t = 0; t < 2; t++) {\n        int x = rng.next_int(0, N - 1);\n        if (st.cellSize[st.cell[x]] > st.cellSize[st.cell[best]]) best = x;\n    }\n    return best;\n}\n\nvector<pair<int,int>> make_candidate_normals(const State& st, const vector<Line>& lines, int want) {\n    vector<pair<int,int>> out;\n    unordered_set<uint64_t> seen;\n    seen.reserve(want * 4 + 32);\n\n    // Fixed useful directions\n    vector<pair<int,int>> fixed = {\n        {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {3,1}, {1,3}\n    };\n    for (auto n : fixed) add_normal(out, seen, n);\n\n    // Existing orientations\n    auto base = unique_normals(lines);\n    shuffle(base.begin(), base.end(), std::mt19937((uint32_t)rng.next()));\n    for (int i = 0; i < (int)base.size() && (int)out.size() < want; i++) {\n        add_normal(out, seen, base[i]);\n    }\n\n    // Combinations of existing orientations\n    int m = min(6, (int)base.size());\n    for (int i = 0; i < m && (int)out.size() < want; i++) {\n        for (int j = i + 1; j < m && (int)out.size() < want; j++) {\n            add_normal(out, seen, combine_normals(base[i], base[j], +1));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, combine_normals(base[i], base[j], -1));\n        }\n    }\n\n    // Normals from pairs inside likely-large cells\n    for (int t = 0; t < 6 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int ci = st.cell[i];\n        int j = -1;\n        for (int rep = 0; rep < 12; rep++) {\n            int x = rng.next_int(0, N - 1);\n            if (x != i && st.cell[x] == ci) {\n                j = x;\n                break;\n            }\n        }\n        if (j != -1) {\n            int dx = pts[j].x - pts[i].x;\n            int dy = pts[j].y - pts[i].y;\n            add_normal(out, seen, normalize_pair(dx, dy));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, normalize_pair(-dy, dx));\n        }\n    }\n\n    // Normals from arbitrary biased pairs\n    for (int t = 0; t < 8 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int j = pick_biased_point(st);\n        if (i == j) continue;\n        int dx = pts[j].x - pts[i].x;\n        int dy = pts[j].y - pts[i].y;\n        add_normal(out, seen, normalize_pair(dx, dy));\n        if ((int)out.size() >= want) break;\n        add_normal(out, seen, normalize_pair(-dy, dx));\n    }\n\n    // Random high-denominator slopes\n    while ((int)out.size() < want) {\n        add_normal(out, seen, random_primitive_large());\n    }\n    return out;\n}\n\nBestLineRes best_line_for_normal(const State& st, pair<int,int> n) {\n    BestLineRes res;\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return res;\n\n    static vector<pair<ll,int>> ord;\n    static vector<int> negCnt, tmpCnt, touched;\n\n    ord.resize(N);\n    for (int i = 0; i < N; i++) {\n        ord[i] = {proj(n.first, n.second, pts[i]), i};\n    }\n    sort(ord.begin(), ord.end());\n\n    int M = (int)st.cellSize.size();\n    negCnt.assign(M, 0);\n    tmpCnt.assign(M, 0);\n    touched.clear();\n\n    auto hist = st.hist;\n    int small = st.smallCount;\n\n    int bestRaw = st.rawScore;\n    int bestSmall = st.smallCount;\n    ll bestC = 0;\n    bool found = false;\n\n    int i = 0;\n    while (i < N) {\n        ll u = ord[i].first;\n        touched.clear();\n        int j = i;\n        while (j < N && ord[j].first == u) {\n            int id = st.cell[ord[j].second];\n            if (tmpCnt[id] == 0) touched.push_back(id);\n            tmpCnt[id]++;\n            j++;\n        }\n\n        for (int id : touched) {\n            int r = tmpCnt[id];\n            tmpCnt[id] = 0;\n\n            int s = st.cellSize[id];\n            int k = negCnt[id];\n            int p = s - k;\n\n            if (1 <= k && k <= 10) { hist[k]--; small--; }\n            if (1 <= p && p <= 10) { hist[p]--; small--; }\n\n            int k2 = k + r;\n            int p2 = s - k2;\n            negCnt[id] = k2;\n\n            if (1 <= k2 && k2 <= 10) { hist[k2]++; small++; }\n            if (1 <= p2 && p2 <= 10) { hist[p2]++; small++; }\n        }\n\n        if (j < N && ord[j].first > u + 1) {\n            int raw = compute_raw_from_hist(hist);\n            if (raw > bestRaw || (raw == bestRaw && small > bestSmall)) {\n                bestRaw = raw;\n                bestSmall = small;\n                bestC = u + 1;\n                found = true;\n            }\n        }\n        i = j;\n    }\n\n    if (!found) return res;\n    res.ok = true;\n    res.raw = bestRaw;\n    res.small = bestSmall;\n    res.line = Line{n.first, n.second, bestC};\n    return res;\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = (a >= 0 ? 1 : -1);\n        y = 0;\n        return std::llabs(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\nll modinv(ll a, ll mod) {\n    if (mod == 1) return 0;\n    ll x, y;\n    ll g = extgcd(a, mod, x, y);\n    if (g != 1) return 0;\n    x %= mod;\n    if (x < 0) x += mod;\n    return x;\n}\n\narray<ll,4> line_to_points(const Line& ln) {\n    const ll LIM = 1000000000LL - 5;\n    ll A = ln.A, B = ln.B, C = ln.C;\n\n    if (B == 0) {\n        // primitive => A=1\n        ll x = C / A;\n        return {x, -LIM, x, LIM};\n    }\n    if (A == 0) {\n        // primitive => B=1\n        ll y = C / B;\n        return {-LIM, y, LIM, y};\n    }\n\n    ll b = std::llabs(B);\n    ll a = ((A % b) + b) % b;\n    ll c = ((C % b) + b) % b;\n    ll inv = modinv(a, b);\n    ll x0 = (ll)((__int128)inv * c % b);\n    ll y0 = (C - A * x0) / B;\n\n    ll t1 = (LIM - std::llabs(x0)) / std::llabs(B);\n    ll t2 = (LIM - std::llabs(y0)) / std::llabs(A);\n    ll t = min(t1, t2);\n    t = min<ll>(t, 200000);\n    if (t < 1) t = 1;\n\n    ll x1 = x0 - B * t;\n    ll y1 = y0 + A * t;\n    ll x2 = x0 + B * t;\n    ll y2 = y0 - A * t;\n\n    while ((std::llabs(x1) > LIM || std::llabs(y1) > LIM ||\n            std::llabs(x2) > LIM || std::llabs(y2) > LIM) && t > 1) {\n        t /= 2;\n        x1 = x0 - B * t;\n        y1 = y0 + A * t;\n        x2 = x0 + B * t;\n        y2 = y0 - A * t;\n    }\n    return {x1, y1, x2, y2};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    for (int d = 1; d <= 10; d++) {\n        cin >> a_need[d];\n        attendees_sum += a_need[d];\n    }\n\n    pts.resize(N);\n    for (int i = 0; i < N; i++) cin >> pts[i].x >> pts[i].y;\n\n    Timer timer;\n\n    const double INITIAL_END = 1.00;\n    const double AUG1_END    = 2.35;\n    const double RETUNE_END  = 2.78;\n    const double AUG2_END    = 2.93;\n\n    double lambdaStar = estimate_lambda_star();\n    double lambdaAvg = max(1.0, (double)N / attendees_sum);\n\n    vector<Line> bestLines;\n    vector<pair<int,int>> bestPrefNormals;\n    int bestRaw = 0;\n\n    // Baseline: 0 cuts\n    {\n        State st = build_state({});\n        bestRaw = st.rawScore;\n        bestLines.clear();\n        bestPrefNormals.clear();\n    }\n\n    // Deterministic-ish 2-bundle seeds\n    {\n        vector<pair<int,int>> seedNormals = {\n            {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}\n        };\n        vector<double> lams = {\n            clampv(lambdaStar * 0.85, 1.0, 12.0),\n            clampv(lambdaStar,        1.0, 12.0),\n            clampv(lambdaStar * 1.15, 1.0, 12.0),\n            clampv(lambdaAvg,         1.0, 12.0),\n        };\n        vector<double> alphas = {0.92, 1.00, 1.10};\n\n        for (auto n0 : seedNormals) {\n            auto n = normalize_pair(n0.first, n0.second);\n            for (double lam : lams) {\n                for (double alpha : alphas) {\n                    Cand2 c;\n                    c.A = n.first;\n                    c.B = n.second;\n                    double Ctarget = N / lam;\n                    double prod = 4.0 * Ctarget / acos(-1.0);\n                    c.t1 = c.t2 = max(1, (int)llround(sqrt(prod) - 1.0));\n                    while (c.t1 + c.t2 > MAX_CUTS) {\n                        if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n                        else if (c.t2 > 1) c.t2--;\n                        else break;\n                    }\n                    c.alpha1 = c.alpha2 = alpha;\n                    c.off1 = c.off2 = 0.0;\n\n                    vector<pair<int,int>> norms;\n                    auto lines = build_lines2(c, norms);\n                    State st = build_state(lines);\n                    if (better_init(st.rawScore, (int)lines.size(), bestRaw, (int)bestLines.size())) {\n                        bestRaw = st.rawScore;\n                        bestLines = lines;\n                        bestPrefNormals = norms;\n                    }\n                }\n            }\n        }\n    }\n\n    // Random search over bundled patterns\n    while (timer.elapsed() < INITIAL_END) {\n        bool use3 = (rng.next() % 10 < 3); // 30% 3-bundle\n        if (!use3) {\n            Cand2 c = random_cand2(lambdaStar);\n            int approx = eval_cand2(c);\n            int cuts = c.t1 + c.t2;\n            if (approx + 2 >= bestRaw || better_init(approx, cuts, bestRaw, (int)bestLines.size())) {\n                vector<pair<int,int>> norms;\n                auto lines = build_lines2(c, norms);\n                State st = build_state(lines);\n                if (better_init(st.rawScore, (int)lines.size(), bestRaw, (int)bestLines.size())) {\n                    bestRaw = st.rawScore;\n                    bestLines = lines;\n                    bestPrefNormals = norms;\n                }\n            }\n        } else {\n            Cand3 c = random_cand3(lambdaStar);\n            int approx = eval_cand3(c);\n            int cuts = c.t[0] + c.t[1] + c.t[2];\n            if (approx + 2 >= bestRaw || better_init(approx, cuts, bestRaw, (int)bestLines.size())) {\n                vector<pair<int,int>> norms;\n                auto lines = build_lines3(c, norms);\n                State st = build_state(lines);\n                if (better_init(st.rawScore, (int)lines.size(), bestRaw, (int)bestLines.size())) {\n                    bestRaw = st.rawScore;\n                    bestLines = lines;\n                    bestPrefNormals = norms;\n                }\n            }\n        }\n    }\n\n    vector<Line> curLines = bestLines;\n    State cur = build_state(curLines);\n\n    // Exact greedy augmentation using exact sweep on candidate normals\n    int stall = 0;\n    while ((int)curLines.size() < K && timer.elapsed() < AUG1_END && stall < 5 && cur.rawScore < attendees_sum) {\n        int want = (timer.elapsed() < 1.8 ? 28 : 22);\n        auto cands = make_candidate_normals(cur, curLines, want);\n\n        BestLineRes best;\n        best.raw = cur.rawScore;\n        best.small = cur.smallCount;\n\n        for (auto n : cands) {\n            auto r = best_line_for_normal(cur, n);\n            if (!r.ok) continue;\n            if (r.raw > best.raw || (r.raw == best.raw && r.small > best.small)) {\n                best = r;\n            }\n        }\n\n        if (best.ok && best.raw > cur.rawScore) {\n            apply_line(cur, best.line);\n            curLines.push_back(best.line);\n            stall = 0;\n        } else {\n            stall++;\n        }\n    }\n\n    // Retune existing lines: remove one line, then re-optimize its threshold exactly with same normal\n    if (!curLines.empty()) {\n        vector<int> order(curLines.size());\n        iota(order.begin(), order.end(), 0);\n        shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next()));\n\n        for (int it = 0; it < (int)order.size() && timer.elapsed() < RETUNE_END; it++) {\n            int idx = order[it];\n            if (idx >= (int)curLines.size()) continue;\n\n            State base = build_state_excluding(curLines, idx);\n            auto n = normalize_pair(curLines[idx].A, curLines[idx].B);\n            auto r = best_line_for_normal(base, n);\n            if (!r.ok) continue;\n\n            if (r.raw > cur.rawScore) {\n                curLines[idx] = r.line;\n                cur = build_state(curLines);\n            }\n        }\n    }\n\n    // Second augmentation pass\n    stall = 0;\n    while ((int)curLines.size() < K && timer.elapsed() < AUG2_END && stall < 4 && cur.rawScore < attendees_sum) {\n        int want = 18;\n        auto cands = make_candidate_normals(cur, curLines, want);\n\n        BestLineRes best;\n        best.raw = cur.rawScore;\n        best.small = cur.smallCount;\n\n        for (auto n : cands) {\n            auto r = best_line_for_normal(cur, n);\n            if (!r.ok) continue;\n            if (r.raw > best.raw || (r.raw == best.raw && r.small > best.small)) {\n                best = r;\n            }\n        }\n\n        if (best.ok && best.raw > cur.rawScore) {\n            apply_line(cur, best.line);\n            curLines.push_back(best.line);\n            stall = 0;\n        } else {\n            stall++;\n        }\n    }\n\n    cout << curLines.size() << '\\n';\n    for (const auto& ln : curLines) {\n        auto p = line_to_points(ln);\n        cout << p[0] << ' ' << p[1] << ' ' << p[2] << ' ' << p[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int MAXID = MAXN * MAXN;\nstatic constexpr int MAXD = 2 * MAXN - 1;\n\nint GX[MAXID], GY[MAXID];\n\ninline int enc(int x, int y) { return y * MAXN + x; }\n\nstruct CoordInit {\n    CoordInit() {\n        for (int y = 0; y < MAXN; ++y) {\n            for (int x = 0; x < MAXN; ++x) {\n                int id = enc(x, y);\n                GX[id] = x;\n                GY[id] = y;\n            }\n        }\n    }\n} coord_init;\n\nstruct Operation {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n};\n\nstruct Candidate {\n    Operation op;\n    double key;\n    int gain;\n    int cost;\n};\n\nstruct Params {\n    double lambda;\n    int topK;\n    int randDepth;\n};\n\nclass Solver {\n    enum Dir {\n        LEFT = 0, RIGHT = 1, DOWN = 2, UP = 3,\n        NE = 4, NW = 5, SW = 6, SE = 7\n    };\n\n    static constexpr int KEEP = 32;\n    static constexpr double EPS = 1e-12;\n\n    int N, M, c;\n    vector<int> initialIds;\n    vector<int> cellOrder;\n    array<pair<int,int>, 8> pairs{\n        pair<int,int>{LEFT, DOWN},\n        pair<int,int>{LEFT, UP},\n        pair<int,int>{RIGHT, DOWN},\n        pair<int,int>{RIGHT, UP},\n        pair<int,int>{NE, NW},\n        pair<int,int>{NE, SE},\n        pair<int,int>{SW, NW},\n        pair<int,int>{SW, SE}\n    };\n\n    int weight[MAXN][MAXN]{};\n\n    // current state\n    unsigned char dot[MAXN][MAXN]{};\n    unsigned char useH[MAXN - 1][MAXN]{};\n    unsigned char useV[MAXN][MAXN - 1]{};\n    unsigned char useD1[MAXN - 1][MAXN - 1]{};\n    unsigned char useD2[MAXN - 1][MAXN - 1]{};\n\n    int nearDot[8][MAXN][MAXN]{};\n\n    int prefH[MAXN][MAXN + 1]{};\n    int prefV[MAXN][MAXN + 1]{};\n    int prefD1[MAXD][MAXN + 1]{};\n    int prefD2[MAXD][MAXN + 1]{};\n\n    long long initialWeight = 0;\n    long long curWeight = 0;\n    long long bestWeight = 0;\n\n    vector<Operation> ops;\n    vector<Operation> bestOps;\n\n    mt19937_64 rng;\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    static bool betterCand(const Candidate& a, const Candidate& b) {\n        if (a.key > b.key + EPS) return true;\n        if (a.key + EPS < b.key) return false;\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return false;\n    }\n\n    void consider(vector<Candidate>& top, const Candidate& cand) {\n        int pos = (int)top.size();\n        while (pos > 0 && betterCand(cand, top[pos - 1])) --pos;\n        if (pos >= KEEP) return;\n        top.insert(top.begin() + pos, cand);\n        if ((int)top.size() > KEEP) top.pop_back();\n    }\n\n    int chooseIndex(int lim) {\n        if (lim <= 1) return 0;\n        uint64_t sum = (uint64_t)lim * (lim + 1) / 2;\n        uint64_t r = rng() % sum;\n        uint64_t acc = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (uint64_t)(lim - i);\n            if (r < acc) return i;\n        }\n        return 0;\n    }\n\n    void resetState() {\n        memset(dot, 0, sizeof(dot));\n        memset(useH, 0, sizeof(useH));\n        memset(useV, 0, sizeof(useV));\n        memset(useD1, 0, sizeof(useD1));\n        memset(useD2, 0, sizeof(useD2));\n        for (int id : initialIds) {\n            dot[GX[id]][GY[id]] = 1;\n        }\n        curWeight = initialWeight;\n        ops.clear();\n    }\n\n    void recomputeAux() {\n        // nearest on rows\n        for (int y = 0; y < N; ++y) {\n            int last = -1;\n            for (int x = 0; x < N; ++x) {\n                nearDot[LEFT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int x = N - 1; x >= 0; --x) {\n                nearDot[RIGHT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // nearest on columns\n        for (int x = 0; x < N; ++x) {\n            int last = -1;\n            for (int y = 0; y < N; ++y) {\n                nearDot[DOWN][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int y = N - 1; y >= 0; --y) {\n                nearDot[UP][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // nearest on main diagonals (x - y = const)\n        for (int d = -(N - 1); d <= (N - 1); ++d) {\n            int minx = max(0, d);\n            int maxx = min(N - 1, N - 1 + d);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = x - d;\n                nearDot[SW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = x - d;\n                nearDot[NE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // nearest on anti-diagonals (x + y = const)\n        for (int s = 0; s <= 2 * (N - 1); ++s) {\n            int minx = max(0, s - (N - 1));\n            int maxx = min(N - 1, s);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = s - x;\n                nearDot[NW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = s - x;\n                nearDot[SE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // prefix sums of used segments\n        for (int y = 0; y < N; ++y) {\n            prefH[y][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int add = (x < N - 1 ? useH[x][y] : 0);\n                prefH[y][x + 1] = prefH[y][x] + add;\n            }\n        }\n\n        for (int x = 0; x < N; ++x) {\n            prefV[x][0] = 0;\n            for (int y = 0; y < N; ++y) {\n                int add = (y < N - 1 ? useV[x][y] : 0);\n                prefV[x][y + 1] = prefV[x][y] + add;\n            }\n        }\n\n        for (int didx = 0; didx < 2 * N - 1; ++didx) {\n            int d = didx - (N - 1);\n            prefD1[didx][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = x - d;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD1[x][y];\n                prefD1[didx][x + 1] = prefD1[didx][x] + add;\n            }\n        }\n\n        for (int s = 0; s < 2 * N - 1; ++s) {\n            prefD2[s][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = s - x - 1;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD2[x][y];\n                prefD2[s][x + 1] = prefD2[s][x] + add;\n            }\n        }\n    }\n\n    int usedCountOnSegment(int x1, int y1, int x2, int y2) const {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefH[y1][r] - prefH[y1][l];\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            return prefV[x1][r] - prefV[x1][l];\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + (N - 1);\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD1[d][r] - prefD1[d][l];\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD2[s][r] - prefD2[s][l];\n        }\n    }\n\n    void markSegment(int x1, int y1, int x2, int y2) {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) useH[x][y1] = 1;\n            return;\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            for (int y = l; y < r; ++y) useV[x1][y] = 1;\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = x - d;\n                useD1[x][y] = 1;\n            }\n            return;\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = s - x - 1;\n                useD2[x][y] = 1;\n            }\n            return;\n        }\n    }\n\n    void apply(const Candidate& cand) {\n        const auto& o = cand.op;\n        dot[o.x1][o.y1] = 1;\n        curWeight += weight[o.x1][o.y1];\n\n        markSegment(o.x1, o.y1, o.x2, o.y2);\n        markSegment(o.x2, o.y2, o.x3, o.y3);\n        markSegment(o.x3, o.y3, o.x4, o.y4);\n        markSegment(o.x4, o.y4, o.x1, o.y1);\n\n        ops.push_back(o);\n    }\n\n    void runAttempt(const Params& prm, chrono::steady_clock::time_point deadline) {\n        resetState();\n        int step = 0;\n\n        while (true) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            recomputeAux();\n\n            vector<Candidate> top;\n            top.reserve(KEEP);\n\n            for (int id1 : cellOrder) {\n                int x = GX[id1], y = GY[id1];\n                if (dot[x][y]) continue;\n\n                int gain = weight[x][y];\n\n                if ((int)top.size() == KEEP) {\n                    double upperBound = gain - prm.lambda * 2.0; // min cost = 1 + 1\n                    if (upperBound + EPS < top.back().key) break;\n                }\n\n                for (auto [da, db] : pairs) {\n                    int id2 = nearDot[da][x][y];\n                    if (id2 < 0) continue;\n                    int id4 = nearDot[db][x][y];\n                    if (id4 < 0) continue;\n\n                    int x2 = GX[id2], y2 = GY[id2];\n                    int x4 = GX[id4], y4 = GY[id4];\n\n                    int x3 = x2 + x4 - x;\n                    int y3 = y2 + y4 - y;\n                    if (!inside(x3, y3)) continue;\n                    if (!dot[x3][y3]) continue;\n\n                    int id3 = enc(x3, y3);\n\n                    // rule 2 (no other dots on perimeter) via nearest-dot relations\n                    if (nearDot[db][x2][y2] != id3) continue;\n                    if (nearDot[da][x4][y4] != id3) continue;\n\n                    // rule 3 (no reused positive-length segment)\n                    if (usedCountOnSegment(x, y, x2, y2)) continue;\n                    if (usedCountOnSegment(x2, y2, x3, y3)) continue;\n                    if (usedCountOnSegment(x3, y3, x4, y4)) continue;\n                    if (usedCountOnSegment(x4, y4, x, y)) continue;\n\n                    int len1 = max(abs(x2 - x), abs(y2 - y));\n                    int len2 = max(abs(x4 - x), abs(y4 - y));\n                    int cost = len1 + len2;\n\n                    Candidate cand{\n                        Operation{x, y, x2, y2, x3, y3, x4, y4},\n                        gain - prm.lambda * cost,\n                        gain,\n                        cost\n                    };\n                    consider(top, cand);\n                }\n            }\n\n            if (top.empty()) break;\n\n            int idx = 0;\n            if (step < prm.randDepth && prm.topK > 1) {\n                idx = chooseIndex(min(prm.topK, (int)top.size()));\n            }\n            apply(top[idx]);\n            ++step;\n        }\n\n        if (curWeight > bestWeight) {\n            bestWeight = curWeight;\n            bestOps = ops;\n        }\n    }\n\npublic:\n    Solver(int N_, int M_, const vector<pair<int,int>>& pts) : N(N_), M(M_), c((N_ - 1) / 2) {\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)N * 1000003ULL;\n        seed ^= (uint64_t)M * 10007ULL;\n        rng.seed(seed);\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                weight[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n                cellOrder.push_back(enc(x, y));\n            }\n        }\n\n        stable_sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n            int xa = GX[a], ya = GY[a];\n            int xb = GX[b], yb = GY[b];\n            if (weight[xa][ya] != weight[xb][yb]) return weight[xa][ya] > weight[xb][yb];\n            int ma = abs(xa - c) + abs(ya - c);\n            int mb = abs(xb - c) + abs(yb - c);\n            if (ma != mb) return ma > mb;\n            return a < b;\n        });\n\n        for (auto [x, y] : pts) {\n            int id = enc(x, y);\n            initialIds.push_back(id);\n            initialWeight += weight[x][y];\n        }\n\n        curWeight = bestWeight = initialWeight;\n        ops.reserve(N * N);\n        bestOps.reserve(N * N);\n    }\n\n    void solve() {\n        auto start = chrono::steady_clock::now();\n        auto deadline = start + chrono::milliseconds(4700);\n\n        vector<Params> fixed = {\n            {12.0, 1, 0},\n            {8.0,  1, 0},\n            {4.0,  1, 0},\n            {2.0,  1, 0},\n            {1.0,  1, 0},\n            {0.5,  1, 0},\n            {0.25, 1, 0},\n            {0.0,  1, 0},\n            {4.0,  4, 10},\n            {2.0,  6, 16},\n            {1.0,  8, 24},\n            {0.5, 10, 32},\n        };\n\n        for (const auto& prm : fixed) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            runAttempt(prm, deadline);\n        }\n\n        static const vector<double> lambdas = {\n            0.0, 0.1, 0.2, 0.35, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 4.0, 6.0, 8.0, 12.0\n        };\n        static const vector<int> ks = {2, 3, 4, 5, 6, 8, 10, 12};\n        static const vector<int> depths = {4, 8, 12, 16, 24, 32, 48, 64};\n\n        while (chrono::steady_clock::now() < deadline) {\n            Params prm;\n            prm.lambda = lambdas[(size_t)(rng() % lambdas.size())];\n            prm.topK = ks[(size_t)(rng() % ks.size())];\n            prm.randDepth = depths[(size_t)(rng() % depths.size())];\n\n            // sometimes run a fully deterministic greedy with a random lambda\n            if ((rng() & 7ULL) == 0) {\n                prm.topK = 1;\n                prm.randDepth = 0;\n            }\n\n            runAttempt(prm, deadline);\n        }\n    }\n\n    void output() const {\n        cout << bestOps.size() << '\\n';\n        for (const auto& o : bestOps) {\n            cout << o.x1 << ' ' << o.y1 << ' '\n                 << o.x2 << ' ' << o.y2 << ' '\n                 << o.x3 << ' ' << o.y3 << ' '\n                 << o.x4 << ' ' << o.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<pair<int,int>> pts(M);\n    for (int i = 0; i < M; ++i) {\n        cin >> pts[i].first >> pts[i].second;\n    }\n\n    Solver solver(N, M, pts);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Board {\n    array<uint8_t, 100> a;\n};\n\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'}; // F: up, B: down, L: left, R: right\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstruct Analysis {\n    int compSq = 0;\n    int largest[4] = {};\n    int compCnt[4] = {};\n    int sameAdj = 0;\n    int diffAdj = 0;\n    int dispersion = 0;\n};\n\nclass Solver {\n    static constexpr double TIME_LIMIT = 1.90;\n\n    int flavor[101]{};\n    int suffixCnt[103][4]{}; // suffixCnt[t][c] = count of flavor c in [t..100]\n    Board cur{};\n    SplitMix64 rng;\n    chrono::steady_clock::time_point st;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    static inline void place_by_rank(Board &b, int rank, int f) {\n        for (int i = 0; i < 100; ++i) {\n            if (b.a[i] == 0) {\n                if (--rank == 0) {\n                    b.a[i] = (uint8_t)f;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline void apply_tilt(const Board &src, int dir, Board &dst) {\n        dst.a.fill(0);\n        if (dir == 0) { // F = up\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 0;\n                for (int r = 0; r < 10; ++r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[ptr++ * 10 + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B = down\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 9;\n                for (int r = 9; r >= 0; --r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[ptr-- * 10 + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L = left\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 0;\n                for (int c = 0; c < 10; ++c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + ptr++] = v;\n                }\n            }\n        } else { // R = right\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 9;\n                for (int c = 9; c >= 0; --c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + ptr--] = v;\n                }\n            }\n        }\n    }\n\n    static int comp_sq_only(const Board &b) {\n        uint8_t vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    static Analysis analyze(const Board &b) {\n        Analysis e;\n        int cnt[4] = {};\n        int sr[4] = {}, sc[4] = {}, sr2[4] = {}, sc2[4] = {};\n\n        for (int r = 0; r < 10; ++r) {\n            for (int c = 0; c < 10; ++c) {\n                int id = r * 10 + c;\n                uint8_t col = b.a[id];\n                if (!col) continue;\n\n                cnt[col]++;\n                sr[col] += r;\n                sc[col] += c;\n                sr2[col] += r * r;\n                sc2[col] += c * c;\n\n                if (c + 1 < 10 && b.a[id + 1]) {\n                    if (b.a[id + 1] == col) e.sameAdj++;\n                    else e.diffAdj++;\n                }\n                if (r + 1 < 10 && b.a[id + 10]) {\n                    if (b.a[id + 10] == col) e.sameAdj++;\n                    else e.diffAdj++;\n                }\n            }\n        }\n\n        uint8_t vis[100] = {};\n        int q[100];\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n\n            e.compSq += sz * sz;\n            e.largest[col] = max(e.largest[col], sz);\n            e.compCnt[col]++;\n        }\n\n        for (int c = 1; c <= 3; ++c) {\n            if (cnt[c] == 0) continue;\n            e.dispersion += cnt[c] * sr2[c] - sr[c] * sr[c];\n            e.dispersion += cnt[c] * sc2[c] - sc[c] * sc[c];\n        }\n\n        return e;\n    }\n\n    long long heuristic(const Board &b, int step) const {\n        Analysis e = analyze(b);\n\n        long long optimistic = e.compSq;\n        long long compPenalty = 0;\n        for (int c = 1; c <= 3; ++c) {\n            int rem = suffixCnt[step + 1][c];\n            optimistic += 2LL * e.largest[c] * rem;\n            compPenalty += 1LL * max(0, e.compCnt[c] - 1) * rem;\n        }\n\n        return optimistic * 1000LL\n             - compPenalty * 200LL\n             + 40LL * e.sameAdj\n             - 25LL * e.diffAdj\n             - 3LL * e.dispersion;\n    }\n\n    double exact_expect(const Board &state_after_tilt, int step) {\n        int next = step + 1;\n        int holes = 101 - next; // number of empty cells before placing candy 'next'\n        double sum = 0.0;\n\n        for (int rank = 1; rank <= holes; ++rank) {\n            Board b = state_after_tilt;\n            place_by_rank(b, rank, flavor[next]);\n\n            if (next == 100) {\n                sum += comp_sq_only(b);\n            } else {\n                double best = -1e100;\n                Board tmp;\n                for (int d = 0; d < 4; ++d) {\n                    apply_tilt(b, d, tmp);\n                    best = max(best, exact_expect(tmp, next));\n                }\n                sum += best;\n            }\n        }\n        return sum / holes;\n    }\n\n    int greedy_best_dir(const Board &after_insert, int step, Board &best_board_out) const {\n        long long bestH = LLONG_MIN;\n        int bestD = 0;\n        Board tmp;\n        for (int d = 0; d < 4; ++d) {\n            apply_tilt(after_insert, d, tmp);\n            long long h = heuristic(tmp, step);\n            if (h > bestH) {\n                bestH = h;\n                bestD = d;\n                best_board_out = tmp;\n            }\n        }\n        return bestD;\n    }\n\n    int choose_dir(const Board &after_insert, int step) {\n        if (step == 100) return 0;\n\n        int rem = 100 - step;\n\n        Board first[4];\n        long long baseH[4];\n        for (int d = 0; d < 4; ++d) {\n            apply_tilt(after_insert, d, first[d]);\n            baseH[d] = heuristic(first[d], step);\n        }\n\n        int greedyBest = 0;\n        for (int d = 1; d < 4; ++d) {\n            if (baseH[d] > baseH[greedyBest]) greedyBest = d;\n        }\n\n        if (elapsed() > TIME_LIMIT - 0.03) return greedyBest;\n\n        // Exact search in the endgame.\n        if (rem <= 5 && elapsed() < TIME_LIMIT - 0.03) {\n            double bestVal = -1e100;\n            int bestD = greedyBest;\n            for (int d = 0; d < 4; ++d) {\n                double v = exact_expect(first[d], step);\n                if (v > bestVal + 1e-12 || (fabs(v - bestVal) <= 1e-12 && baseH[d] > baseH[bestD])) {\n                    bestVal = v;\n                    bestD = d;\n                }\n            }\n            return bestD;\n        }\n\n        // Monte Carlo with common random numbers.\n        int K = min(20, max(4, 400 / rem));\n        long long sumFinal[4] = {};\n        int done = 0;\n\n        int ranks[101];\n        for (int k = 0; k < K; ++k) {\n            if (elapsed() > TIME_LIMIT - 0.03) break;\n\n            for (int u = step + 1; u <= 100; ++u) {\n                ranks[u] = 1 + rng.next_int(101 - u);\n            }\n\n            for (int d = 0; d < 4; ++d) {\n                Board sim = first[d];\n                for (int u = step + 1; u <= 100; ++u) {\n                    place_by_rank(sim, ranks[u], flavor[u]);\n                    if (u == 100) break;\n\n                    Board nextBestBoard;\n                    greedy_best_dir(sim, u, nextBestBoard);\n                    sim = nextBestBoard;\n                }\n                sumFinal[d] += comp_sq_only(sim);\n            }\n            ++done;\n        }\n\n        if (done == 0) return greedyBest;\n\n        double bestScore = -1e100;\n        int bestD = greedyBest;\n        for (int d = 0; d < 4; ++d) {\n            double avgFinal = (double)sumFinal[d] / done;\n            double score = avgFinal * 3000.0 + (double)baseH[d];\n            if (score > bestScore) {\n                bestScore = score;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 1; i <= 100; ++i) cin >> flavor[i];\n\n        for (int c = 1; c <= 3; ++c) suffixCnt[101][c] = 0;\n        for (int t = 100; t >= 1; --t) {\n            for (int c = 1; c <= 3; ++c) suffixCnt[t][c] = suffixCnt[t + 1][c];\n            suffixCnt[t][flavor[t]]++;\n        }\n\n        uint64_t seed = 0x123456789abcdefULL;\n        for (int i = 1; i <= 100; ++i) {\n            seed = seed * 6364136223846793005ULL + (uint64_t)(flavor[i] + 1);\n        }\n        rng = SplitMix64(seed);\n\n        cur.a.fill(0);\n        st = chrono::steady_clock::now();\n\n        for (int t = 1; t <= 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place_by_rank(cur, p, flavor[t]);\n\n            int d = choose_dir(cur, t);\n\n            Board nxt;\n            apply_tilt(cur, d, nxt);\n            cur = nxt;\n\n            cout << DIR_CH[d] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Candidate {\n    vector<int> parts;   // partition of B, nondecreasing\n    vector<int> deg;     // base sorted degree vector, length B\n    int edgeCnt = 0;     // base edge count\n};\n\nstatic long long dist2_deg(const vector<int>& a, const vector<int>& b) {\n    long long s = 0;\n    for (int i = 0; i < (int)a.size(); i++) {\n        long long d = (long long)a[i] - b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstatic vector<Candidate> generate_partitions(int B) {\n    vector<Candidate> res;\n    vector<int> cur;\n\n    function<void(int,int)> dfs = [&](int rem, int last) {\n        if (rem == 0) {\n            Candidate c;\n            c.parts = cur;\n            c.deg.reserve(B);\n            int edges = 0;\n            for (int s : cur) {\n                edges += s * (s - 1) / 2;\n                for (int t = 0; t < s; t++) c.deg.push_back(s - 1);\n            }\n            c.edgeCnt = edges;\n            res.push_back(std::move(c));\n            return;\n        }\n        for (int x = last; x <= rem; x++) {\n            cur.push_back(x);\n            dfs(rem - x, x);\n            cur.pop_back();\n        }\n    };\n    dfs(B, 1);\n    return res;\n}\n\nstatic double selection_quality(const vector<Candidate>& cands, const vector<int>& sel) {\n    int m = (int)sel.size();\n    if (m <= 1) return 0.0;\n    long long sum_nn = 0;\n    for (int i = 0; i < m; i++) {\n        long long best = (1LL << 60);\n        for (int j = 0; j < m; j++) if (i != j) {\n            best = min(best, dist2_deg(cands[sel[i]].deg, cands[sel[j]].deg));\n        }\n        sum_nn += best;\n    }\n    return (double)sum_nn / m;\n}\n\nstatic vector<Candidate> select_codewords(const vector<Candidate>& cands, int M) {\n    int C = (int)cands.size();\n    if (C <= M) {\n        vector<Candidate> ret = cands;\n        sort(ret.begin(), ret.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.edgeCnt != b.edgeCnt) return a.edgeCnt < b.edgeCnt;\n            return a.parts < b.parts;\n        });\n        return ret;\n    }\n\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int i, int j) {\n        if (cands[i].edgeCnt != cands[j].edgeCnt) return cands[i].edgeCnt < cands[j].edgeCnt;\n        return cands[i].parts < cands[j].parts;\n    });\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQual = -1.0;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<long long> minDist(C, (1LL << 60));\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                long long d = dist2_deg(cands[x].deg, cands[i].deg);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        };\n\n        add_one(seed);\n        if (M >= 2) {\n            int far = -1;\n            long long best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                long long d = dist2_deg(cands[seed].deg, cands[i].deg);\n                if (d > best) {\n                    best = d;\n                    far = i;\n                }\n            }\n            add_one(far);\n        }\n\n        while ((int)sel.size() < M) {\n            int nxt = -1;\n            long long best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double qual = selection_quality(cands, sel);\n        if (qual > bestQual) {\n            bestQual = qual;\n            bestSel = sel;\n        }\n    }\n\n    vector<Candidate> ret;\n    ret.reserve(M);\n    for (int id : bestSel) ret.push_back(cands[id]);\n    sort(ret.begin(), ret.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.edgeCnt != b.edgeCnt) return a.edgeCnt < b.edgeCnt;\n        return a.parts < b.parts;\n    });\n    return ret;\n}\n\nstatic vector<double> build_expected_degree_vector(const vector<int>& parts, int q, double eps) {\n    int B = 0;\n    for (int x : parts) B += x;\n    int N = B * q;\n    double shift = eps * (N - 1);\n    double scale = 1.0 - 2.0 * eps;\n\n    vector<double> mu;\n    mu.reserve(N);\n    for (int x : parts) {\n        int s = x * q;\n        double v = shift + scale * (s - 1);\n        for (int i = 0; i < s; i++) mu.push_back(v);\n    }\n    return mu;\n}\n\nstatic string build_graph_string(const vector<int>& parts, int q) {\n    int B = 0;\n    for (int x : parts) B += x;\n    int N = B * q;\n\n    vector<int> block(N);\n    int ptr = 0, bid = 0;\n    for (int x : parts) {\n        int s = x * q;\n        for (int i = 0; i < s; i++) block[ptr++] = bid;\n        ++bid;\n    }\n\n    string g;\n    g.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            g.push_back(block[i] == block[j] ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic vector<int> q_candidates(int qmax) {\n    vector<int> qs;\n    if (qmax <= 12) {\n        for (int q = 1; q <= qmax; q++) qs.push_back(q);\n    } else {\n        for (int q = 1; q <= 8; q++) qs.push_back(q);\n        for (int q : {10, 12, 14, 16, 18, 20}) if (q <= qmax) qs.push_back(q);\n        qs.push_back(qmax);\n        sort(qs.begin(), qs.end());\n        qs.erase(unique(qs.begin(), qs.end()), qs.end());\n    }\n    return qs;\n}\n\nstatic double estimate_proxy_score(\n    const vector<Candidate>& codes, int B, int q, int M, double eps, int reps\n) {\n    int N = B * q;\n    double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n\n    vector<vector<double>> exps(M);\n    for (int i = 0; i < M; i++) {\n        exps[i] = build_expected_degree_vector(codes[i].parts, q, eps);\n    }\n\n    mt19937_64 rng(0x123456789ULL + 10007ULL * B + 1000003ULL * q);\n    normal_distribution<double> gauss(0.0, sigma);\n\n    int err = 0;\n    int tot = M * reps;\n    vector<double> noisy(N);\n\n    for (int rep = 0; rep < reps; rep++) {\n        for (int i = 0; i < M; i++) {\n            const auto& mu = exps[i];\n            for (int j = 0; j < N; j++) {\n                double x = mu[j];\n                if (sigma > 0) x += gauss(rng);\n                x = std::clamp(x, 0.0, (double)(N - 1));\n                x = std::round(x);\n                noisy[j] = x;\n            }\n            sort(noisy.begin(), noisy.end());\n\n            int bestId = -1;\n            double bestS = 1e100;\n            for (int t = 0; t < M; t++) {\n                const auto& v = exps[t];\n                double s = 0.0;\n                for (int j = 0; j < N; j++) {\n                    double d = noisy[j] - v[j];\n                    s += d * d;\n                    if (s >= bestS) break;\n                }\n                if (s < bestS) {\n                    bestS = s;\n                    bestId = t;\n                }\n            }\n            if (bestId != i) err++;\n        }\n    }\n\n    double errRate = (double)err / tot;\n    return pow(0.9, 100.0 * errRate) / N;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    // partition numbers p(n) up to 25\n    const int BMAX = 23;\n    vector<long long> p(BMAX + 1, 0);\n    p[0] = 1;\n    for (int x = 1; x <= BMAX; x++) {\n        for (int s = x; s <= BMAX; s++) p[s] += p[s - x];\n    }\n\n    int Bmin = 1;\n    while (Bmin <= BMAX && p[Bmin] < M) Bmin++;\n    if (Bmin > BMAX) Bmin = BMAX;\n\n    int Bhi = min(BMAX, Bmin + 10);\n\n    struct BaseBook {\n        int B;\n        vector<Candidate> codes;\n    };\n    vector<BaseBook> books;\n\n    for (int B = Bmin; B <= Bhi; B++) {\n        auto cands = generate_partitions(B);\n        if ((int)cands.size() < M) continue;\n        auto codes = select_codewords(cands, M);\n        books.push_back({B, std::move(codes)});\n    }\n\n    int bestB = -1, bestQ = -1, bestN = -1;\n    double bestScore = -1.0;\n    vector<Candidate> bestCodes;\n\n    const int reps = 2;\n\n    for (const auto& book : books) {\n        int B = book.B;\n        int qmax = 100 / B;\n        auto coarseQs = q_candidates(qmax);\n\n        double localBestScore = -1.0;\n        int localBestQ = -1;\n\n        set<int> evaluated;\n        auto try_q = [&](int q) {\n            if (q < 1 || q > qmax) return;\n            if (!evaluated.insert(q).second) return;\n\n            double sc = estimate_proxy_score(book.codes, B, q, M, eps, reps);\n            int N = B * q;\n            if (sc > localBestScore + 1e-15 ||\n                (abs(sc - localBestScore) <= 1e-15 && (localBestQ == -1 || N < B * localBestQ))) {\n                localBestScore = sc;\n                localBestQ = q;\n            }\n        };\n\n        for (int q : coarseQs) try_q(q);\n        for (int q = localBestQ - 2; q <= localBestQ + 2; q++) try_q(q);\n\n        int N = B * localBestQ;\n        if (localBestScore > bestScore + 1e-15 ||\n            (abs(localBestScore - bestScore) <= 1e-15 && (bestN == -1 || N < bestN))) {\n            bestScore = localBestScore;\n            bestB = B;\n            bestQ = localBestQ;\n            bestN = N;\n            bestCodes = book.codes;\n        }\n    }\n\n    if (bestB == -1) {\n        // fallback, should never happen\n        bestB = Bmin;\n        bestQ = 1;\n        bestN = bestB;\n        auto cands = generate_partitions(bestB);\n        bestCodes = select_codewords(cands, M);\n    }\n\n    const int N = bestB * bestQ;\n\n    vector<string> graphStrs(M);\n    vector<vector<double>> expDeg(M);\n    for (int i = 0; i < M; i++) {\n        graphStrs[i] = build_graph_string(bestCodes[i].parts, bestQ);\n        expDeg[i] = build_expected_degree_vector(bestCodes[i].parts, bestQ, eps);\n    }\n\n    cout << N << '\\n';\n    for (int i = 0; i < M; i++) {\n        cout << graphStrs[i] << '\\n';\n    }\n    cout.flush();\n\n    for (int query = 0; query < 100; query++) {\n        string H;\n        cin >> H;\n        if (!cin) return 0;\n\n        vector<int> deg(N, 0);\n        int pos = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                if (H[pos++] == '1') {\n                    deg[i]++;\n                    deg[j]++;\n                }\n            }\n        }\n        sort(deg.begin(), deg.end());\n\n        int ans = 0;\n        double bestS = 1e100;\n        for (int k = 0; k < M; k++) {\n            const auto& mu = expDeg[k];\n            double s = 0.0;\n            for (int i = 0; i < N; i++) {\n                double d = deg[i] - mu[i];\n                s += d * d;\n                if (s >= bestS) break;\n            }\n            if (s < bestS) {\n                bestS = s;\n                ans = k;\n            }\n        }\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x += 0x9e3779b97f4a7c15ull;\n        uint64_t z = x;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& a) {\n        for (int i = (int)a.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(a[i], a[j]);\n        }\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n    double mx, my;\n};\n\nstruct Adj {\n    int to, eid;\n};\n\nstruct PairW {\n    int a, b;\n    double w;\n};\n\nstruct State {\n    vector<int> day;       // size M\n    vector<int> cnt;       // size D\n    vector<double> load;   // normalized importance load per day\n    vector<double> same;   // size M*D, same[e*D+d] = conflict sum if e put on d\n};\n\nclass Solver {\n    static constexpr ll INF = (1LL << 60);\n    static constexpr ll UNREACH = 1000000000LL;\n    static constexpr double PI = 3.14159265358979323846;\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Adj>> g;\n    vector<pair<int,int>> pos;\n    vector<vector<int>> incident;\n    vector<int> degv;\n\n    double centroidX = 0.0, centroidY = 0.0;\n\n    vector<int> sources;\n    int S = 0;\n    vector<vector<ll>> baseDist; // S x N\n\n    vector<double> imp, impN;\n    vector<PairW> conflicts;\n    vector<vector<pair<int,double>>> neigh;\n    vector<double> neighSum;\n    double targetCnt = 0.0;\n    double targetLoad = 0.0;\n\n    chrono::steady_clock::time_point start_time;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    inline double& SAME(State& st, int e, int d) {\n        return st.same[(size_t)e * D + d];\n    }\n    inline double SAMEC(const State& st, int e, int d) const {\n        return st.same[(size_t)e * D + d];\n    }\n\n    void dijkstra_internal(int src, int banDay, const vector<int>& day,\n                           vector<ll>& dist,\n                           vector<int>* parentV = nullptr,\n                           vector<int>* parentE = nullptr) {\n        dist.assign(N, INF);\n        if (parentV) parentV->assign(N, -1);\n        if (parentE) parentE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n\n            for (const auto& a : g[v]) {\n                if (banDay >= 0 && day[a.eid] == banDay) continue;\n                int to = a.to;\n                ll nd = cd + edges[a.eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parentV) (*parentV)[to] = v;\n                    if (parentE) (*parentE)[to] = a.eid;\n                    pq.push({nd, to});\n                } else if (parentV && nd == dist[to]) {\n                    if ((*parentE)[to] == -1 || a.eid < (*parentE)[to]) {\n                        (*parentV)[to] = v;\n                        (*parentE)[to] = a.eid;\n                    }\n                }\n            }\n        }\n    }\n\n    void choose_sources() {\n        S = min(12, N);\n\n        // first source near centroid\n        int first = 0;\n        double best = 1e100;\n        for (int i = 0; i < N; ++i) {\n            double dx = pos[i].first - centroidX;\n            double dy = pos[i].second - centroidY;\n            double d2 = dx * dx + dy * dy;\n            if (d2 < best) {\n                best = d2;\n                first = i;\n            }\n        }\n\n        sources.clear();\n        vector<double> minD2(N, 1e100);\n\n        int cur = first;\n        for (int t = 0; t < S; ++t) {\n            sources.push_back(cur);\n            for (int i = 0; i < N; ++i) {\n                double dx = pos[i].first - pos[cur].first;\n                double dy = pos[i].second - pos[cur].second;\n                double d2 = dx * dx + dy * dy;\n                if (d2 < minD2[i]) minD2[i] = d2;\n            }\n            int nxt = -1;\n            double farv = -1.0;\n            for (int i = 0; i < N; ++i) {\n                bool used = false;\n                for (int s : sources) if (s == i) { used = true; break; }\n                if (used) continue;\n                if (minD2[i] > farv) {\n                    farv = minD2[i];\n                    nxt = i;\n                }\n            }\n            if (nxt == -1) break;\n            cur = nxt;\n        }\n        S = (int)sources.size();\n    }\n\n    void compute_importance() {\n        choose_sources();\n        baseDist.assign(S, vector<ll>(N));\n\n        double avgw = 0.0;\n        for (auto& e : edges) avgw += e.w;\n        avgw /= M;\n\n        vector<double> usage(M, 0.0);\n        vector<ll> dist;\n        vector<int> pv, pe;\n\n        vector<int> emptyDay; // banDay < 0 => ignored\n\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, -1, emptyDay, dist, &pv, &pe);\n            baseDist[si] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sub(N, 1);\n            for (int v : ord) {\n                if (v == src) continue;\n                if (pe[v] != -1) {\n                    usage[pe[v]] += sub[v];\n                    sub[pv[v]] += sub[v];\n                }\n            }\n        }\n\n        imp.assign(M, 1.0);\n        for (int e = 0; e < M; ++e) {\n            double wf = sqrt((double)edges[e].w / avgw);\n            imp[e] = sqrt(1.0 + usage[e]) * (0.7 + 0.3 * wf);\n        }\n\n        double avgImp = 0.0;\n        for (double x : imp) avgImp += x;\n        avgImp /= M;\n\n        impN.resize(M);\n        for (int e = 0; e < M; ++e) impN[e] = imp[e] / avgImp;\n\n        targetCnt = (double)M / D;\n        double sumImpN = 0.0;\n        for (double x : impN) sumImpN += x;\n        targetLoad = sumImpN / D;\n    }\n\n    void build_conflicts() {\n        struct Tmp {\n            int a, b;\n            double w;\n        };\n        vector<Tmp> tmp;\n        tmp.reserve(200000);\n\n        // strong conflicts for edges sharing a vertex\n        for (int v = 0; v < N; ++v) {\n            auto& inc = incident[v];\n            int deg = (int)inc.size();\n            double lowFactor = 1.0 + 0.8 * max(0, 5 - deg); // deg2 -> strong\n            for (int i = 0; i < deg; ++i) {\n                for (int j = i + 1; j < deg; ++j) {\n                    int a = inc[i], b = inc[j];\n                    if (a > b) swap(a, b);\n                    double w = 40.0 * lowFactor * (0.7 + 0.15 * (impN[a] + impN[b]));\n                    tmp.push_back({a, b, w});\n                }\n            }\n        }\n\n        // medium conflicts for spatially close edges\n        const double R = 110.0;\n        const double R2 = R * R;\n        const int CELL = 110;\n        const int G = 1000 / CELL + 4;\n\n        auto cell_id = [&](int x, int y) {\n            return x * G + y;\n        };\n\n        vector<vector<int>> cells(G * G);\n        for (int e = 0; e < M; ++e) {\n            int cx = min(G - 1, max(0, (int)(edges[e].mx / CELL)));\n            int cy = min(G - 1, max(0, (int)(edges[e].my / CELL)));\n            cells[cell_id(cx, cy)].push_back(e);\n        }\n\n        auto share_vertex = [&](int a, int b) -> bool {\n            const auto& A = edges[a];\n            const auto& B = edges[b];\n            return A.u == B.u || A.u == B.v || A.v == B.u || A.v == B.v;\n        };\n\n        for (int x = 0; x < G; ++x) {\n            for (int y = 0; y < G; ++y) {\n                int id1 = cell_id(x, y);\n                for (int nx = max(0, x - 1); nx <= min(G - 1, x + 1); ++nx) {\n                    for (int ny = max(0, y - 1); ny <= min(G - 1, y + 1); ++ny) {\n                        if (nx < x || (nx == x && ny < y)) continue;\n                        int id2 = cell_id(nx, ny);\n                        const auto& c1 = cells[id1];\n                        const auto& c2 = cells[id2];\n                        if (id1 == id2) {\n                            for (int i = 0; i < (int)c1.size(); ++i) {\n                                for (int j = i + 1; j < (int)c1.size(); ++j) {\n                                    int a = c1[i], b = c1[j];\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        if (a > b) swap(a, b);\n                                        tmp.push_back({a, b, w});\n                                    }\n                                }\n                            }\n                        } else {\n                            for (int a : c1) {\n                                for (int b : c2) {\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        int x1 = a, x2 = b;\n                                        if (x1 > x2) swap(x1, x2);\n                                        tmp.push_back({x1, x2, w});\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        sort(tmp.begin(), tmp.end(), [&](const Tmp& p, const Tmp& q) {\n            if (p.a != q.a) return p.a < q.a;\n            return p.b < q.b;\n        });\n\n        conflicts.clear();\n        for (int i = 0; i < (int)tmp.size(); ) {\n            int j = i + 1;\n            double sw = tmp[i].w;\n            while (j < (int)tmp.size() && tmp[j].a == tmp[i].a && tmp[j].b == tmp[i].b) {\n                sw += tmp[j].w;\n                ++j;\n            }\n            conflicts.push_back({tmp[i].a, tmp[i].b, sw});\n            i = j;\n        }\n\n        neigh.assign(M, {});\n        neighSum.assign(M, 0.0);\n        for (auto& p : conflicts) {\n            neigh[p.a].push_back({p.b, p.w});\n            neigh[p.b].push_back({p.a, p.w});\n            neighSum[p.a] += p.w;\n            neighSum[p.b] += p.w;\n        }\n    }\n\n    inline double add_cost(int cnt, double load, double ie, double lc, double li) const {\n        double dc = (cnt + 1 - targetCnt) * (cnt + 1 - targetCnt) - (cnt - targetCnt) * (cnt - targetCnt);\n        double dl = (load + ie - targetLoad) * (load + ie - targetLoad) - (load - targetLoad) * (load - targetLoad);\n        return lc * dc + li * dl;\n    }\n\n    inline double move_delta_proxy(const State& st, int e, int b, double lc, double li) const {\n        int a = st.day[e];\n        if (a == b) return 0.0;\n        if (st.cnt[b] >= K) return 1e100;\n\n        double pairDelta = SAMEC(st, e, b) - SAMEC(st, e, a);\n\n        double dc =\n            (st.cnt[a] - 1 - targetCnt) * (st.cnt[a] - 1 - targetCnt) +\n            (st.cnt[b] + 1 - targetCnt) * (st.cnt[b] + 1 - targetCnt) -\n            (st.cnt[a] - targetCnt) * (st.cnt[a] - targetCnt) -\n            (st.cnt[b] - targetCnt) * (st.cnt[b] - targetCnt);\n\n        double ie = impN[e];\n        double dl =\n            (st.load[a] - ie - targetLoad) * (st.load[a] - ie - targetLoad) +\n            (st.load[b] + ie - targetLoad) * (st.load[b] + ie - targetLoad) -\n            (st.load[a] - targetLoad) * (st.load[a] - targetLoad) -\n            (st.load[b] - targetLoad) * (st.load[b] - targetLoad);\n\n        return pairDelta + lc * dc + li * dl;\n    }\n\n    void apply_move(State& st, int e, int b) {\n        int a = st.day[e];\n        if (a == b) return;\n        st.cnt[a]--;\n        st.cnt[b]++;\n        st.load[a] -= impN[e];\n        st.load[b] += impN[e];\n\n        for (auto [f, w] : neigh[e]) {\n            SAME(st, f, a) -= w;\n            SAME(st, f, b) += w;\n        }\n        st.day[e] = b;\n    }\n\n    State build_state(const vector<int>& day) {\n        State st;\n        st.day = day;\n        st.cnt.assign(D, 0);\n        st.load.assign(D, 0.0);\n\n        for (int e = 0; e < M; ++e) {\n            st.cnt[day[e]]++;\n            st.load[day[e]] += impN[e];\n        }\n\n        st.same.assign((size_t)M * D, 0.0);\n        for (auto& p : conflicts) {\n            SAME(st, p.a, st.day[p.b]) += p.w;\n            SAME(st, p.b, st.day[p.a]) += p.w;\n        }\n        return st;\n    }\n\n    vector<int> construct_initial(int type, RNG& rng, double lc, double li) {\n        vector<int> order;\n        order.reserve(M);\n        vector<int> pref(M, -1);\n\n        if (type == 0) {\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = neighSum[e] + 5.0 * impN[e] + 3.0 * rng.next_double();\n                arr.push_back({-key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n        } else if (type == 1) {\n            double th = rng.next_double() * 2.0 * PI;\n            double cs = cos(th), sn = sin(th);\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = edges[e].mx * cs + edges[e].my * sn + 1e-6 * rng.next_double();\n                arr.push_back({key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        } else {\n            double shift = rng.next_double() * 2.0 * PI;\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double ang = atan2(edges[e].my - centroidY, edges[e].mx - centroidX) - shift;\n                while (ang < 0) ang += 2.0 * PI;\n                while (ang >= 2.0 * PI) ang -= 2.0 * PI;\n                arr.push_back({ang + 1e-6 * rng.next_double(), e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        }\n\n        double prefPenalty = 8.0 + 6.0 * rng.next_double();\n\n        vector<int> day(M, -1);\n        vector<int> cnt(D, 0);\n        vector<double> load(D, 0.0);\n        array<double, 32> tmpConf{};\n\n        for (int e : order) {\n            for (int d = 0; d < D; ++d) tmpConf[d] = 0.0;\n            for (auto [f, w] : neigh[e]) {\n                int df = day[f];\n                if (df != -1) tmpConf[df] += w;\n            }\n\n            int bestd = -1;\n            double bestScore = 1e100;\n            int offset = rng.next_int(D);\n\n            for (int zz = 0; zz < D; ++zz) {\n                int d = (offset + zz) % D;\n                if (cnt[d] >= K) continue;\n                double sc = tmpConf[d] + add_cost(cnt[d], load[d], impN[e], lc, li);\n                if (pref[e] != -1 && d != pref[e]) sc += prefPenalty;\n                sc += 1e-7 * rng.next_double();\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestd = d;\n                }\n            }\n\n            if (bestd == -1) {\n                // fallback, should not happen\n                bestd = 0;\n                while (cnt[bestd] >= K) ++bestd;\n            }\n\n            day[e] = bestd;\n            cnt[bestd]++;\n            load[bestd] += impN[e];\n        }\n\n        return day;\n    }\n\n    void proxy_improve(State& st, RNG& rng, double lc, double li) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < 8; ++pass) {\n            rng.shuffle_vec(ord);\n            int moved = 0;\n\n            for (int e : ord) {\n                int a = st.day[e];\n                int bestd = a;\n                double bestDelta = -1e-9;\n\n                int offset = rng.next_int(D);\n                for (int zz = 0; zz < D; ++zz) {\n                    int d = (offset + zz) % D;\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                    }\n                }\n\n                if (bestd != a) {\n                    apply_move(st, e, bestd);\n                    moved++;\n                }\n            }\n\n            if (moved == 0) break;\n            if (elapsed() > 4.5) break;\n        }\n    }\n\n    ll eval_day_cost(int banDay, const vector<int>& day) {\n        ll res = 0;\n        vector<ll> dist;\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, banDay, day, dist, nullptr, nullptr);\n            const auto& bd = baseDist[si];\n            for (int v = 0; v < N; ++v) {\n                if (v == src) continue;\n                ll nd = (dist[v] >= INF / 2 ? UNREACH : dist[v]);\n                res += nd - bd[v];\n            }\n        }\n        return res;\n    }\n\n    ll eval_schedule(const vector<int>& day, const vector<int>& cnt, vector<ll>& dayCost) {\n        dayCost.assign(D, 0);\n        ll total = 0;\n        for (int d = 0; d < D; ++d) {\n            if (cnt[d] == 0) continue;\n            dayCost[d] = eval_day_cost(d, day);\n            total += dayCost[d];\n        }\n        return total;\n    }\n\n    void actual_refine(vector<int>& bestDay, double lc, double li) {\n        State st = build_state(bestDay);\n        vector<ll> dayCost;\n        ll curScore = eval_schedule(st.day, st.cnt, dayCost);\n\n        int accepted = 0;\n        while (elapsed() < 5.45 && accepted < 25) {\n            vector<int> worstOrd(D);\n            iota(worstOrd.begin(), worstOrd.end(), 0);\n            sort(worstOrd.begin(), worstOrd.end(), [&](int a, int b) {\n                return dayCost[a] > dayCost[b];\n            });\n\n            int takeDays = min(3, D);\n            array<int, 32> isTop{};\n            for (int i = 0; i < takeDays; ++i) isTop[worstOrd[i]] = 1;\n\n            vector<pair<double,int>> candEdges;\n            candEdges.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                int d = st.day[e];\n                if (!isTop[d]) continue;\n                double score = SAMEC(st, e, d) + 4.0 * impN[e];\n                candEdges.push_back({-score, e});\n            }\n\n            if (candEdges.empty()) break;\n            sort(candEdges.begin(), candEdges.end());\n            if ((int)candEdges.size() > 50) candEdges.resize(50);\n\n            vector<int> lowOrd(D);\n            iota(lowOrd.begin(), lowOrd.end(), 0);\n            sort(lowOrd.begin(), lowOrd.end(), [&](int a, int b) {\n                return dayCost[a] < dayCost[b];\n            });\n\n            bool moved = false;\n\n            for (auto [negScore, e] : candEdges) {\n                if (elapsed() > 5.45) break;\n\n                int a = st.day[e];\n                vector<pair<double,int>> pd;\n                pd.reserve(D);\n\n                for (int d = 0; d < D; ++d) {\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    pd.push_back({delta, d});\n                }\n                if (pd.empty()) continue;\n\n                sort(pd.begin(), pd.end());\n                vector<int> candDays;\n                for (int i = 0; i < (int)pd.size() && i < 4; ++i) candDays.push_back(pd[i].second);\n                for (int i = 0; i < min(2, D); ++i) {\n                    int d = lowOrd[i];\n                    if (d == a || st.cnt[d] >= K) continue;\n                    bool found = false;\n                    for (int x : candDays) if (x == d) found = true;\n                    if (!found) candDays.push_back(d);\n                }\n\n                ll bestDelta = 0;\n                int bestd = -1;\n                ll bestA = 0, bestB = 0;\n\n                int old = st.day[e];\n                for (int d : candDays) {\n                    st.day[e] = d;\n                    ll na = eval_day_cost(a, st.day);\n                    ll nb = eval_day_cost(d, st.day);\n                    ll delta = (na + nb) - (dayCost[a] + dayCost[d]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                        bestA = na;\n                        bestB = nb;\n                    }\n                }\n                st.day[e] = old;\n\n                if (bestd != -1) {\n                    apply_move(st, e, bestd);\n                    dayCost[a] = bestA;\n                    dayCost[bestd] = bestB;\n                    curScore += bestDelta;\n                    accepted++;\n                    moved = true;\n                    break;\n                }\n            }\n\n            if (!moved) break;\n        }\n\n        bestDay = st.day;\n        (void)curScore;\n    }\n\npublic:\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(N, {});\n        degv.assign(N, 0);\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            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            degv[u]++;\n            degv[v]++;\n        }\n\n        pos.resize(N);\n        for (int i = 0; i < N; ++i) {\n            cin >> pos[i].first >> pos[i].second;\n            centroidX += pos[i].first;\n            centroidY += pos[i].second;\n        }\n        centroidX /= N;\n        centroidY /= N;\n\n        for (int i = 0; i < M; ++i) {\n            edges[i].mx = 0.5 * (pos[edges[i].u].first + pos[edges[i].v].first);\n            edges[i].my = 0.5 * (pos[edges[i].u].second + pos[edges[i].v].second);\n        }\n\n        compute_importance();\n        build_conflicts();\n\n        uint64_t seedBase = 1469598103934665603ull;\n        seedBase ^= (uint64_t)N + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)M + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)D + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)K + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n\n        vector<int> bestDay;\n        ll bestScore = (1LL << 62);\n        double bestLc = 4.5, bestLi = 2.0;\n\n        int runs = 0;\n        while (elapsed() < 3.8 && runs < 12) {\n            RNG rng(seedBase + 1000003ull * (uint64_t)runs + 1234567ull);\n\n            double lc = 3.5 + 2.5 * rng.next_double();\n            double li = 1.5 + 2.0 * rng.next_double();\n\n            int type = runs % 3;\n            vector<int> initDay = construct_initial(type, rng, lc, li);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, lc, li);\n\n            vector<ll> dayCost;\n            ll sc = eval_schedule(st.day, st.cnt, dayCost);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestDay = st.day;\n                bestLc = lc;\n                bestLi = li;\n            }\n            runs++;\n        }\n\n        if (bestDay.empty()) {\n            RNG rng(seedBase);\n            vector<int> initDay = construct_initial(0, rng, 4.5, 2.0);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, 4.5, 2.0);\n            bestDay = st.day;\n        }\n\n        actual_refine(bestDay, bestLc, bestLi);\n\n        for (int i = 0; i < M; ++i) {\n            if (i) cout << ' ';\n            cout << bestDay[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\nstatic constexpr int MAXD = 14;\nstatic constexpr int MAXN = MAXD * MAXD * MAXD;\nstatic constexpr int NEG_INF = -1e9;\n\nint D, Ncells;\n\nstring fstr[2][MAXD], rstr[2][MAXD];\nuint16_t actXMask[2][MAXD], actYMask[2][MAXD];\nvector<int> actXList[2][MAXD], actYList[2][MAXD];\nuint8_t activeCell[2][MAXD][MAXD][MAXD]; // [obj][x][y][z]\n\nchrono::steady_clock::time_point g_start;\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\ninline void decode3(int id, int &x, int &y, int &z) {\n    x = id / (D * D);\n    int rem = id % (D * D);\n    y = rem / D;\n    z = rem % D;\n}\n\nstruct Comp {\n    vector<int> cells;\n    int vol = 0;\n};\n\nstruct Seg {\n    int x, y, z0, len;\n};\n\nstruct SegCmp {\n    bool operator()(const Seg& a, const Seg& b) const {\n        if (a.len != b.len) return a.len < b.len;\n        if (a.x != b.x) return a.x > b.x;\n        if (a.y != b.y) return a.y > b.y;\n        return a.z0 > b.z0;\n    }\n};\n\nstruct Candidate {\n    array<uint8_t, MAXN> occ{};\n    vector<Seg> segs;\n};\n\nstruct CoreInfo {\n    vector<char> keep;\n    long double scoreCore = 0.0L;\n    uint16_t covX[MAXD]{};\n    uint16_t covY[MAXD]{};\n    uint16_t coreRow[MAXD][MAXD]{}; // bitmask of y for each (z,x)\n    int remVol[2]{};\n};\n\nstruct Param {\n    int dir;   // +1 forward, -1 backward\n    int alpha; // continuation reward\n    int beta;  // future run reward\n    int seed;  // tie-break diversity\n};\n\nvector<Comp> comps;\n\n// per-threshold run lengths for extra-available cells\nint runF[2][MAXD][MAXD][MAXD + 1];\nint runB[2][MAXD][MAXD][MAXD];\n\ninline int popcnt16(uint16_t x) {\n    return __builtin_popcount((unsigned)x);\n}\n\nuint32_t tiny_hash(uint32_t x) {\n    x ^= x >> 16;\n    x *= 0x7feb352dU;\n    x ^= x >> 15;\n    x *= 0x846ca68bU;\n    x ^= x >> 16;\n    return x;\n}\n\ninline int tiny_noise(int seed, int x, int y, int z) {\n    uint32_t v = (uint32_t)seed * 1000003u\n               ^ (uint32_t)(x + 1) * 911382323u\n               ^ (uint32_t)(y + 1) * 972663749u\n               ^ (uint32_t)(z + 1) * 19260817u;\n    return (int)(tiny_hash(v) & 31u); // 0..31\n}\n\nvoid build_full_common_components() {\n    vector<uint8_t> common(Ncells, 0);\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 (activeCell[0][x][y][z] && activeCell[1][x][y][z]) {\n                    common[idx3(x, y, z)] = 1;\n                }\n            }\n        }\n    }\n\n    vector<uint8_t> vis(Ncells, 0);\n    const int dx[6] = {1, -1, 0, 0, 0, 0};\n    const int dy[6] = {0, 0, 1, -1, 0, 0};\n    const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    for (int s = 0; s < Ncells; s++) {\n        if (!common[s] || vis[s]) continue;\n        queue<int> q;\n        q.push(s);\n        vis[s] = 1;\n        Comp c;\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (common[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        comps.push_back(std::move(c));\n    }\n}\n\nvoid extract_segments(const array<uint8_t, MAXN>& occ, vector<Seg>& segs) {\n    segs.clear();\n    for (int x = 0; x < D; x++) {\n        for (int y = 0; y < D; y++) {\n            int z = 0;\n            while (z < D) {\n                while (z < D && !occ[idx3(x, y, z)]) z++;\n                if (z == D) break;\n                int z0 = z;\n                while (z < D && occ[idx3(x, y, z)]) z++;\n                segs.push_back({x, y, z0, z - z0});\n            }\n        }\n    }\n}\n\nlong double match_score_segs(const vector<Seg>& s1, const vector<Seg>& s2) {\n    priority_queue<int> pq1, pq2;\n    for (auto &s : s1) pq1.push(s.len);\n    for (auto &s : s2) pq2.push(s.len);\n\n    long double sc = 0.0L;\n    long long exclusive = 0;\n\n    while (!pq1.empty() && !pq2.empty()) {\n        int a = pq1.top(); pq1.pop();\n        int b = pq2.top(); pq2.pop();\n        int m = min(a, b);\n        sc += 1.0L / (long double)m;\n        if (a > m) pq1.push(a - m);\n        if (b > m) pq2.push(b - m);\n    }\n    while (!pq1.empty()) {\n        exclusive += pq1.top();\n        pq1.pop();\n    }\n    while (!pq2.empty()) {\n        exclusive += pq2.top();\n        pq2.pop();\n    }\n    sc += (long double)exclusive;\n    return sc;\n}\n\nCoreInfo build_core_by_threshold(int threshold) {\n    CoreInfo core;\n    core.keep.assign(comps.size(), 0);\n\n    for (int z = 0; z < D; z++) {\n        core.covX[z] = 0;\n        core.covY[z] = 0;\n        for (int x = 0; x < D; x++) core.coreRow[z][x] = 0;\n    }\n\n    for (int cid = 0; cid < (int)comps.size(); cid++) {\n        if (comps[cid].vol > threshold) {\n            core.keep[cid] = 1;\n            core.scoreCore += 1.0L / (long double)comps[cid].vol;\n            for (int id : comps[cid].cells) {\n                int x, y, z;\n                decode3(id, x, y, z);\n                core.covX[z] |= (uint16_t(1) << x);\n                core.covY[z] |= (uint16_t(1) << y);\n                core.coreRow[z][x] |= (uint16_t(1) << y);\n            }\n        }\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        int vol = 0;\n        for (int z = 0; z < D; z++) {\n            int ur = popcnt16(actXMask[obj][z] & ~core.covX[z]);\n            int uc = popcnt16(actYMask[obj][z] & ~core.covY[z]);\n            vol += max(ur, uc);\n        }\n        core.remVol[obj] = vol;\n    }\n\n    return core;\n}\n\nvoid build_runs(const CoreInfo& core) {\n    for (int obj = 0; obj < 2; obj++) {\n        for (int x = 0; x < D; x++) {\n            for (int y = 0; y < D; y++) {\n                runF[obj][x][y][D] = 0;\n                for (int z = D - 1; z >= 0; z--) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runF[obj][x][y][z] = avail ? 1 + runF[obj][x][y][z + 1] : 0;\n                }\n                for (int z = 0; z < D; z++) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runB[obj][x][y][z] = avail ? 1 + (z ? runB[obj][x][y][z - 1] : 0) : 0;\n                }\n            }\n        }\n    }\n}\n\n// domain items choose one among `choices`, while every `mandatory` value must be used at least once\n// values are actual coordinates in 0..D-1\nvector<int> solve_dp_assignment(\n    const vector<int>& domain,\n    const vector<int>& choices,\n    const vector<int>& mandatory,\n    int w[MAXD][MAXD]\n) {\n    int p = (int)domain.size();\n    int q = (int)choices.size();\n    int m = (int)mandatory.size();\n\n    vector<int> ret(p, 0);\n    if (p == 0) return ret;\n\n    int pos[ MAXD ];\n    for (int i = 0; i < MAXD; i++) pos[i] = -1;\n    for (int i = 0; i < m; i++) pos[mandatory[i]] = i;\n\n    int bitOfChoice[MAXD];\n    for (int j = 0; j < q; j++) {\n        bitOfChoice[j] = (pos[choices[j]] == -1 ? 0 : (1 << pos[choices[j]]));\n    }\n\n    int S = 1 << m;\n    static int dp[1 << MAXD], ndp[1 << MAXD];\n    static uint16_t parentMask[MAXD + 1][1 << MAXD];\n    static int8_t parentChoice[MAXD + 1][1 << MAXD];\n\n    for (int mask = 0; mask < S; mask++) dp[mask] = NEG_INF;\n    dp[0] = 0;\n\n    for (int i = 0; i < p; i++) {\n        for (int mask = 0; mask < S; mask++) ndp[mask] = NEG_INF;\n        for (int mask = 0; mask < S; mask++) if (dp[mask] > NEG_INF / 2) {\n            for (int j = 0; j < q; j++) {\n                int ww = w[i][j];\n                if (ww <= NEG_INF / 2) continue;\n                int nmask = mask | bitOfChoice[j];\n                int val = dp[mask] + ww;\n                if (val > ndp[nmask]) {\n                    ndp[nmask] = val;\n                    parentMask[i + 1][nmask] = (uint16_t)mask;\n                    parentChoice[i + 1][nmask] = (int8_t)j;\n                }\n            }\n        }\n        for (int mask = 0; mask < S; mask++) dp[mask] = ndp[mask];\n    }\n\n    int full = S - 1;\n    if (dp[full] <= NEG_INF / 2) {\n        // robust fallback\n        for (int i = 0; i < p; i++) {\n            int bestj = 0, bestv = NEG_INF;\n            for (int j = 0; j < q; j++) {\n                if (w[i][j] > bestv) {\n                    bestv = w[i][j];\n                    bestj = j;\n                }\n            }\n            ret[i] = bestj;\n        }\n        return ret;\n    }\n\n    int mask = full;\n    for (int i = p; i >= 1; i--) {\n        int j = parentChoice[i][mask];\n        ret[i - 1] = j;\n        mask = parentMask[i][mask];\n    }\n    return ret;\n}\n\nCandidate build_candidate(int obj, const CoreInfo& core, const Param& prm) {\n    Candidate cand;\n    cand.occ.fill(0);\n\n    uint16_t prevRow[MAXD]{};\n    uint16_t curRow[MAXD]{};\n\n    int zStart = (prm.dir == 1 ? 0 : D - 1);\n    int zEnd   = (prm.dir == 1 ? D : -1);\n    int zStep  = (prm.dir == 1 ? 1 : -1);\n\n    for (int z = zStart; z != zEnd; z += zStep) {\n        for (int x = 0; x < D; x++) curRow[x] = 0;\n\n        vector<int> uncRows, uncCols;\n        uncRows.reserve(D);\n        uncCols.reserve(D);\n\n        uint16_t rowMask = actXMask[obj][z] & ~core.covX[z];\n        uint16_t colMask = actYMask[obj][z] & ~core.covY[z];\n\n        for (int x : actXList[obj][z]) if ((rowMask >> x) & 1) uncRows.push_back(x);\n        for (int y : actYList[obj][z]) if ((colMask >> y) & 1) uncCols.push_back(y);\n\n        if (uncRows.empty() && uncCols.empty()) {\n            memcpy(prevRow, curRow, sizeof(prevRow));\n            continue;\n        }\n\n        int w[MAXD][MAXD];\n        for (int i = 0; i < MAXD; i++) for (int j = 0; j < MAXD; j++) w[i][j] = NEG_INF;\n\n        if ((int)uncRows.size() >= (int)uncCols.size()) {\n            const vector<int>& domain = uncRows;\n            const vector<int>& choices = actYList[obj][z];\n            const vector<int>& mandatory = uncCols;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int y = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue; // should not happen, but safe\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                int y = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        } else {\n            const vector<int>& domain = uncCols;\n            const vector<int>& choices = actXList[obj][z];\n            const vector<int>& mandatory = uncRows;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int x = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue; // safe\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                int x = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        }\n\n        memcpy(prevRow, curRow, sizeof(prevRow));\n    }\n\n    extract_segments(cand.occ, cand.segs);\n    return cand;\n}\n\nvoid assign_final_labels(\n    const CoreInfo& core,\n    const array<uint8_t, MAXN>& extra1,\n    const array<uint8_t, MAXN>& extra2,\n    array<int, MAXN>& out1,\n    array<int, MAXN>& out2,\n    int& nblocks\n) {\n    out1.fill(0);\n    out2.fill(0);\n    nblocks = 0;\n\n    // shared exact-core components\n    for (int cid = 0; cid < (int)comps.size(); cid++) {\n        if (!core.keep[cid]) continue;\n        ++nblocks;\n        for (int id : comps[cid].cells) {\n            out1[id] = nblocks;\n            out2[id] = nblocks;\n        }\n    }\n\n    vector<Seg> s1, s2;\n    extract_segments(extra1, s1);\n    extract_segments(extra2, s2);\n\n    priority_queue<Seg, vector<Seg>, SegCmp> pq1, pq2;\n    for (auto &s : s1) pq1.push(s);\n    for (auto &s : s2) pq2.push(s);\n\n    auto fill_seg = [&](array<int, MAXN>& out, const Seg& s, int len, int label) {\n        for (int t = 0; t < len; t++) {\n            out[idx3(s.x, s.y, s.z0 + t)] = label;\n        }\n    };\n\n    while (!pq1.empty() && !pq2.empty()) {\n        Seg a = pq1.top(); pq1.pop();\n        Seg b = pq2.top(); pq2.pop();\n        int m = min(a.len, b.len);\n        ++nblocks;\n        fill_seg(out1, a, m, nblocks);\n        fill_seg(out2, b, m, nblocks);\n\n        if (a.len > m) {\n            a.z0 += m;\n            a.len -= m;\n            pq1.push(a);\n        }\n        if (b.len > m) {\n            b.z0 += m;\n            b.len -= m;\n            pq2.push(b);\n        }\n    }\n    while (!pq1.empty()) {\n        Seg a = pq1.top(); pq1.pop();\n        ++nblocks;\n        fill_seg(out1, a, a.len, nblocks);\n    }\n    while (!pq2.empty()) {\n        Seg b = pq2.top(); pq2.pop();\n        ++nblocks;\n        fill_seg(out2, b, b.len, nblocks);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> D;\n    Ncells = D * D * D;\n\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) cin >> fstr[i][z];\n        for (int z = 0; z < D; z++) cin >> rstr[i][z];\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        for (int z = 0; z < D; z++) {\n            actXMask[obj][z] = 0;\n            actYMask[obj][z] = 0;\n            actXList[obj][z].clear();\n            actYList[obj][z].clear();\n\n            for (int x = 0; x < D; x++) {\n                if (fstr[obj][z][x] == '1') {\n                    actXMask[obj][z] |= (uint16_t(1) << x);\n                    actXList[obj][z].push_back(x);\n                }\n            }\n            for (int y = 0; y < D; y++) {\n                if (rstr[obj][z][y] == '1') {\n                    actYMask[obj][z] |= (uint16_t(1) << y);\n                    actYList[obj][z].push_back(y);\n                }\n            }\n\n            for (int x = 0; x < D; x++) {\n                for (int y = 0; y < D; y++) {\n                    activeCell[obj][x][y][z] =\n                        (fstr[obj][z][x] == '1' && rstr[obj][z][y] == '1') ? 1 : 0;\n                }\n            }\n        }\n    }\n\n    build_full_common_components();\n\n    vector<Param> params = {\n        {+1, 100000,   0, 1},\n        {-1, 100000,   0, 1},\n        {+1,  20000, 200, 2},\n        {-1,  20000, 200, 2},\n    };\n\n    vector<int> thresholds = {-1, 1, 3, 7, (int)1e9};\n\n    long double bestScore = 1e100L;\n    CoreInfo bestCore;\n    array<uint8_t, MAXN> bestOcc1{}, bestOcc2{};\n    bool found = false;\n\n    for (int th : thresholds) {\n        if (elapsed_sec() > 5.45) break;\n\n        CoreInfo core = build_core_by_threshold(th);\n\n        long double lowerBound = core.scoreCore + (long double)abs(core.remVol[0] - core.remVol[1]);\n        if (found && lowerBound >= bestScore - 1e-15L) continue;\n\n        build_runs(core);\n\n        vector<Candidate> cand[2];\n\n        for (int obj = 0; obj < 2; obj++) {\n            for (auto &prm : params) {\n                if (elapsed_sec() > 5.55 && !cand[obj].empty()) break;\n                cand[obj].push_back(build_candidate(obj, core, prm));\n            }\n            if (cand[obj].empty()) {\n                cand[obj].push_back(build_candidate(obj, core, params[0]));\n            }\n        }\n\n        for (auto &c1 : cand[0]) {\n            for (auto &c2 : cand[1]) {\n                long double sc = core.scoreCore + match_score_segs(c1.segs, c2.segs);\n                if (!found || sc < bestScore) {\n                    found = true;\n                    bestScore = sc;\n                    bestCore = core;\n                    bestOcc1 = c1.occ;\n                    bestOcc2 = c2.occ;\n                }\n            }\n        }\n    }\n\n    if (!found) {\n        CoreInfo core = build_core_by_threshold((int)1e9);\n        build_runs(core);\n        Candidate c1 = build_candidate(0, core, {+1, 100000, 0, 1});\n        Candidate c2 = build_candidate(1, core, {+1, 100000, 0, 1});\n        bestCore = core;\n        bestOcc1 = c1.occ;\n        bestOcc2 = c2.occ;\n    }\n\n    array<int, MAXN> out1, out2;\n    int nblocks = 0;\n    assign_final_labels(bestCore, bestOcc1, bestOcc2, out1, out2, nblocks);\n\n    cout << nblocks << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out2[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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 leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n};\n\nstruct Candidate {\n    vector<int> P;\n    vector<char> B;\n    int covered = -1;\n    long long cost = (1LL << 62);\n};\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> B;\n};\n\nclass Solver {\npublic:\n    int N, M, K;\n    vector<int> xs, ys;\n    vector<Edge> edges;\n    vector<int> as, bs;\n\n    vector<vector<int>> req; // req[i][k] = minimum power to cover resident k, or 5001\n    vector<vector<pair<int,int>>> lists; // (required power, resident id), sorted\n    vector<vector<int>> incident;\n    vector<vector<int>> eidMat;\n\n    vector<vector<long long>> sp;\n    vector<vector<int>> nxt;\n\n    chrono::steady_clock::time_point t0;\n    static constexpr long long INF64 = (1LL << 60);\n    static constexpr double HARD_LIMIT = 1.92;\n\n    void input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> K;\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n        edges.resize(M);\n        incident.assign(N, {});\n        eidMat.assign(N, vector<int>(N, -1));\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, v, w};\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            eidMat[u][v] = eidMat[v][u] = i;\n        }\n\n        as.resize(K);\n        bs.resize(K);\n        for (int k = 0; k < K; k++) cin >> as[k] >> bs[k];\n    }\n\n    double elapsed() const {\n        auto t = chrono::steady_clock::now();\n        return chrono::duration<double>(t - t0).count();\n    }\n\n    static int ceil_sqrt_ll(long long x) {\n        long long r = sqrt((long double)x);\n        while (r * r < x) ++r;\n        while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n        return (int)r;\n    }\n\n    void precompute() {\n        req.assign(N, vector<int>(K, 5001));\n        lists.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            lists[i].reserve(K / 2);\n            for (int k = 0; k < K; k++) {\n                long long dx = (long long)xs[i] - as[k];\n                long long dy = (long long)ys[i] - bs[k];\n                long long d2 = dx * dx + dy * dy;\n                int r = ceil_sqrt_ll(d2);\n                if (r <= 5000) {\n                    req[i][k] = r;\n                    lists[i].push_back({r, k});\n                }\n            }\n            sort(lists[i].begin(), lists[i].end());\n        }\n\n        sp.assign(N, vector<long long>(N, INF64));\n        nxt.assign(N, vector<int>(N, -1));\n        for (int i = 0; i < N; i++) {\n            sp[i][i] = 0;\n            nxt[i][i] = i;\n        }\n        for (int e = 0; e < M; e++) {\n            auto [u, v, w] = edges[e];\n            if (w < sp[u][v]) {\n                sp[u][v] = sp[v][u] = w;\n                nxt[u][v] = v;\n                nxt[v][u] = u;\n            }\n        }\n        for (int k = 0; k < N; k++) {\n            for (int i = 0; i < N; i++) if (sp[i][k] < INF64) {\n                for (int j = 0; j < N; j++) if (sp[k][j] < INF64) {\n                    long long nd = sp[i][k] + sp[k][j];\n                    if (nd < sp[i][j]) {\n                        sp[i][j] = nd;\n                        nxt[i][j] = nxt[i][k];\n                    }\n                }\n            }\n        }\n\n        t0 = chrono::steady_clock::now();\n    }\n\n    vector<long double> make_gain_table(long double gamma) const {\n        vector<long double> gain(K + 1, 0);\n        if (fabsl(gamma - 1.0L) < 1e-18L) {\n            for (int i = 1; i <= K; i++) gain[i] = (long double)i;\n        } else {\n            for (int i = 1; i <= K; i++) gain[i] = powl((long double)i, gamma);\n        }\n        return gain;\n    }\n\n    vector<int> reconstruct_path_vertices(int s, int t) const {\n        vector<int> path;\n        if (nxt[s][t] == -1) return path;\n        int cur = s;\n        path.push_back(cur);\n        while (cur != t) {\n            cur = nxt[cur][t];\n            path.push_back(cur);\n        }\n        return path;\n    }\n\n    void recompute_nearest_tree(\n        const vector<char>& inTree,\n        vector<long long>& distToTree,\n        vector<int>& nearTree\n    ) const {\n        distToTree.assign(N, INF64);\n        nearTree.assign(N, -1);\n        for (int i = 0; i < N; i++) {\n            if (inTree[i]) {\n                distToTree[i] = 0;\n                nearTree[i] = i;\n                continue;\n            }\n            long long best = INF64;\n            int bestv = -1;\n            for (int v = 0; v < N; v++) if (inTree[v]) {\n                if (sp[v][i] < best) {\n                    best = sp[v][i];\n                    bestv = v;\n                }\n            }\n            distToTree[i] = best;\n            nearTree[i] = bestv;\n        }\n    }\n\n    long long edge_cost(const vector<char>& B) const {\n        long long c = 0;\n        for (int i = 0; i < M; i++) if (B[i]) c += edges[i].w;\n        return c;\n    }\n\n    long long power_cost(const vector<int>& P) const {\n        long long c = 0;\n        for (int i = 0; i < N; i++) c += 1LL * P[i] * P[i];\n        return c;\n    }\n\n    vector<char> terminals_from_P(const vector<int>& P) const {\n        vector<char> term(N, 0);\n        term[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) term[i] = 1;\n        return term;\n    }\n\n    vector<char> tree_vertices(const vector<char>& B) const {\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 (int eid : incident[v]) if (B[eid]) {\n                int to = edges[eid].u ^ edges[eid].v ^ v;\n                if (!vis[to]) {\n                    vis[to] = 1;\n                    q.push(to);\n                }\n            }\n        }\n        return vis;\n    }\n\n    vector<int> degrees_from_B(const vector<char>& B) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        return deg;\n    }\n\n    void prune_nonterminal_leaves(vector<char>& B, const vector<char>& terminal) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n\n        queue<int> q;\n        for (int v = 0; v < N; v++) {\n            if (v != 0 && !terminal[v] && deg[v] == 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            if (v == 0 || terminal[v] || deg[v] != 1) continue;\n\n            int remE = -1, to = -1;\n            for (int eid : incident[v]) if (B[eid]) {\n                remE = eid;\n                to = edges[eid].u ^ edges[eid].v ^ v;\n                break;\n            }\n            if (remE == -1) continue;\n\n            B[remE] = 0;\n            deg[v]--;\n            deg[to]--;\n            if (to != 0 && !terminal[to] && deg[to] == 1) q.push(to);\n        }\n    }\n\n    vector<char> build_tree_metric(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n\n        vector<int> ids;\n        ids.push_back(0);\n        for (int i = 1; i < N; i++) if (terminal[i]) ids.push_back(i);\n\n        int T = (int)ids.size();\n        if (T <= 1) return used;\n\n        // Prim on metric closure.\n        vector<long long> minD(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> vis(T, 0);\n        minD[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            for (int i = 0; i < T; i++) {\n                if (!vis[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            vis[v] = 1;\n            for (int u = 0; u < T; u++) if (!vis[u]) {\n                if (sp[ids[v]][ids[u]] < minD[u]) {\n                    minD[u] = sp[ids[v]][ids[u]];\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<char> cand(M, 0);\n        vector<int> candEdges;\n        for (int i = 1; i < T; i++) {\n            auto path = reconstruct_path_vertices(ids[i], ids[par[i]]);\n            for (int j = 0; j + 1 < (int)path.size(); j++) {\n                int a = path[j], b = path[j + 1];\n                int eid = eidMat[a][b];\n                if (eid >= 0 && !cand[eid]) {\n                    cand[eid] = 1;\n                    candEdges.push_back(eid);\n                }\n            }\n        }\n\n        sort(candEdges.begin(), candEdges.end(), [&](int e1, int e2) {\n            if (edges[e1].w != edges[e2].w) return edges[e1].w < edges[e2].w;\n            return e1 < e2;\n        });\n\n        DSU dsu(N);\n        for (int eid : candEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            if (dsu.merge(u, v)) used[eid] = 1;\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_sph(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n        vector<char> inTree(N, 0);\n        vector<char> left = terminal;\n        inTree[0] = 1;\n        left[0] = 0;\n\n        int rem = 0;\n        for (int i = 0; i < N; i++) if (left[i]) rem++;\n\n        if (rem == 0) return used;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        while (rem > 0) {\n            int best = -1;\n            long long bestD = INF64;\n            for (int i = 0; i < N; i++) if (left[i]) {\n                if (distToTree[i] < bestD) {\n                    bestD = distToTree[i];\n                    best = i;\n                }\n            }\n            if (best == -1) break;\n\n            int from = nearTree[best];\n            auto path = reconstruct_path_vertices(from, best);\n\n            int lastTreeIdx = 0;\n            for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n            for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                int u = path[i], v = path[i + 1];\n                int eid = eidMat[u][v];\n                if (eid >= 0) used[eid] = 1;\n                inTree[u] = 1;\n                inTree[v] = 1;\n            }\n            left[best] = 0;\n            rem--;\n\n            recompute_nearest_tree(inTree, distToTree, nearTree);\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_best(const vector<char>& terminal) const {\n        auto b1 = build_tree_metric(terminal);\n        auto b2 = build_tree_sph(terminal);\n        if (edge_cost(b2) < edge_cost(b1)) return b2;\n        return b1;\n    }\n\n    Candidate make_candidate(const vector<int>& Pin, const vector<char>& Bin) const {\n        vector<int> P = Pin;\n        vector<char> B = Bin;\n\n        // Remove disconnected parts.\n        vector<char> reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n        for (int e = 0; e < M; e++) if (B[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (!(reach[u] && reach[v])) B[e] = 0;\n        }\n\n        vector<char> terminal(N, 0);\n        terminal[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) terminal[i] = 1;\n        prune_nonterminal_leaves(B, terminal);\n\n        reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (reach[i] && P[i] > 0) active.push_back(i);\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n\n        long long cost = power_cost(P) + edge_cost(B);\n        return {P, B, cov, cost};\n    }\n\n    static bool better(const Candidate& a, const Candidate& b, int K) {\n        if (a.covered != b.covered) return a.covered > b.covered;\n        if (a.covered == K) return a.cost < b.cost;\n        return a.cost < b.cost;\n    }\n\n    int count_covered_by_P(const vector<int>& P) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        if (active.empty()) return 0;\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n        return cov;\n    }\n\n    bool covers_need(const vector<int>& P, const vector<char>& need) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (need[k]) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n        return true;\n    }\n\n    void reduce_powers(vector<int>& P, const vector<char>& allowed) const {\n        while (true) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) {\n                if (allowed[i] && P[i] > 0) active.push_back(i);\n            }\n            sort(active.begin(), active.end(), [&](int a, int b) {\n                if (P[a] != P[b]) return P[a] > P[b];\n                return a < b;\n            });\n\n            bool changed = false;\n            for (int i : active) {\n                int newP = 0;\n                for (const auto& [d, rid] : lists[i]) {\n                    if (d > P[i]) break;\n                    bool other = false;\n                    for (int j : active) {\n                        if (j == i || P[j] == 0) continue;\n                        if (req[j][rid] <= P[j]) {\n                            other = true;\n                            break;\n                        }\n                    }\n                    if (!other) newP = d;\n                }\n                if (newP < P[i]) {\n                    P[i] = newP;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    vector<int> greedy_cover_subset(\n        const vector<char>& allowed,\n        const vector<int>& Pinit,\n        const vector<char>& needMask,\n        long double gamma,\n        int banned = -1\n    ) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P = Pinit;\n        vector<char> uncoveredNeed = needMask;\n\n        int rem = 0;\n        for (int k = 0; k < K; k++) if (needMask[k]) rem++;\n\n        if (rem == 0) return P;\n\n        // Remove already-covered needed residents.\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (uncoveredNeed[k]) {\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    uncoveredNeed[k] = 0;\n                    rem--;\n                    break;\n                }\n            }\n        }\n        if (rem == 0) return P;\n\n        vector<int> curPos(N, 0);\n        for (int i = 0; i < N; i++) {\n            auto it = upper_bound(lists[i].begin(), lists[i].end(),\n                                  make_pair(P[i], INT_MAX));\n            curPos[i] = (int)(it - lists[i].begin());\n        }\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                if (!allowed[i] || i == banned) continue;\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (uncoveredNeed[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq);\n                    long double metric = num / gain[newcov];\n\n                    bool take = false;\n                    if (metric < bestMetric - 1e-18L) take = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) take = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) take = true;\n                    }\n\n                    if (take) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (uncoveredNeed[rid]) {\n                    uncoveredNeed[rid] = 0;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return P;\n    }\n\n    vector<int> greedy_on_allowed_gamma(const vector<char>& allowed, long double gamma, int banned = -1) const {\n        vector<int> P0(N, 0);\n        vector<char> need(K, 1);\n        return greedy_cover_subset(allowed, P0, need, gamma, banned);\n    }\n\n    InitialState greedy_initial(long double alpha, long double gamma) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P(N, 0);\n        vector<int> curPos(N, 0);\n        vector<char> covered(K, 0);\n        vector<char> usedEdge(M, 0);\n        vector<char> inTree(N, 0);\n        inTree[0] = 1;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        int rem = K;\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                long double conn = inTree[i] ? 0.0L : alpha * (long double)distToTree[i];\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (!covered[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq) + conn;\n                    long double metric = num / gain[newcov];\n\n                    bool better = false;\n                    if (metric < bestMetric - 1e-18L) better = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) better = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) better = true;\n                    }\n                    if (better) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            if (!inTree[bestStation]) {\n                int from = nearTree[bestStation];\n                auto path = reconstruct_path_vertices(from, bestStation);\n\n                int lastTreeIdx = 0;\n                for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n                for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                    int u = path[i], v = path[i + 1];\n                    int eid = eidMat[u][v];\n                    if (eid >= 0) usedEdge[eid] = 1;\n                    inTree[u] = 1;\n                    inTree[v] = 1;\n                }\n\n                recompute_nearest_tree(inTree, distToTree, nearTree);\n            }\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (!covered[rid]) {\n                    covered[rid] = 1;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return {P, usedEdge};\n    }\n\n    Candidate basic_improve(Candidate cur, int rounds) const {\n        for (int it = 0; it < rounds; it++) {\n            if (elapsed() > HARD_LIMIT) break;\n\n            Candidate bestRound = cur;\n\n            auto B0 = build_tree_best(terminals_from_P(cur.P));\n            Candidate c0 = make_candidate(cur.P, B0);\n            if (better(c0, bestRound, K)) bestRound = c0;\n\n            vector<char> allowed = tree_vertices(bestRound.B);\n\n            static const long double gammas[] = {1.0L, 1.10L};\n            for (long double g : gammas) {\n                if (elapsed() > HARD_LIMIT) break;\n                vector<int> P = greedy_on_allowed_gamma(allowed, g);\n                if (count_covered_by_P(P) < K) continue;\n                reduce_powers(P, allowed);\n                auto B = build_tree_best(terminals_from_P(P));\n                Candidate c = make_candidate(P, B);\n                if (better(c, bestRound, K)) bestRound = c;\n            }\n\n            if (better(bestRound, cur, K)) cur = bestRound;\n            else break;\n        }\n        return cur;\n    }\n\n    Candidate try_remove_station(const Candidate& cur, const vector<char>& allowed, int s) const {\n        Candidate best = cur;\n        if (cur.P[s] == 0) return best;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n\n        vector<char> need(K, 0);\n        int needCnt = 0;\n        for (int k = 0; k < K; k++) {\n            if (req[s][k] > cur.P[s]) continue;\n            bool other = false;\n            for (int i : active) {\n                if (i == s) continue;\n                if (req[i][k] <= cur.P[i]) {\n                    other = true;\n                    break;\n                }\n            }\n            if (!other) {\n                need[k] = 1;\n                needCnt++;\n            }\n        }\n\n        vector<int> baseP = cur.P;\n        baseP[s] = 0;\n\n        auto relax_from_P = [&](vector<int> P) {\n            if (elapsed() > HARD_LIMIT) return;\n            if (count_covered_by_P(P) < K) return;\n            reduce_powers(P, allowed);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate c = make_candidate(P, B);\n            if (better(c, best, K)) best = c;\n        };\n\n        if (needCnt == 0) {\n            relax_from_P(baseP);\n        } else {\n            vector<int> P1 = greedy_cover_subset(allowed, baseP, need, 1.0L, s);\n            if (covers_need(P1, need)) relax_from_P(P1);\n\n            if (elapsed() <= HARD_LIMIT) {\n                vector<int> P2 = greedy_cover_subset(allowed, baseP, need, 1.10L, s);\n                if (covers_need(P2, need)) relax_from_P(P2);\n            }\n        }\n\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P3 = greedy_on_allowed_gamma(allowed, 1.0L, s);\n            relax_from_P(P3);\n        }\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P4 = greedy_on_allowed_gamma(allowed, 1.10L, s);\n            relax_from_P(P4);\n        }\n\n        return best;\n    }\n\n    Candidate local_remove(Candidate cur) const {\n        while (elapsed() < HARD_LIMIT) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n            if (active.empty()) break;\n\n            vector<char> allowed = tree_vertices(cur.B);\n            vector<int> deg = degrees_from_B(cur.B);\n\n            vector<int> byPower = active;\n            sort(byPower.begin(), byPower.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> leafs;\n            for (int v : active) if (deg[v] == 1) leafs.push_back(v);\n            sort(leafs.begin(), leafs.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> trials;\n            auto push_unique = [&](int v) {\n                for (int x : trials) if (x == v) return;\n                trials.push_back(v);\n            };\n\n            for (int i = 0; i < (int)leafs.size() && i < 6; i++) push_unique(leafs[i]);\n            for (int i = 0; i < (int)byPower.size() && i < 8; i++) push_unique(byPower[i]);\n\n            bool improved = false;\n            for (int s : trials) {\n                if (elapsed() > HARD_LIMIT) break;\n                Candidate cand = try_remove_station(cur, allowed, s);\n                if (better(cand, cur, K)) {\n                    cur = basic_improve(cand, 1);\n                    improved = true;\n                    break;\n                }\n            }\n            if (!improved) break;\n        }\n        return cur;\n    }\n\n    Candidate solve() {\n        Candidate best;\n\n        auto consider = [&](Candidate c, int rounds = 3) {\n            if (elapsed() > HARD_LIMIT) return;\n            c = basic_improve(c, rounds);\n            if (better(c, best, K)) best = c;\n        };\n\n        vector<pair<long double,long double>> connectedParams = {\n            {0.00L, 1.00L},\n            {0.20L, 1.00L},\n            {0.55L, 1.00L},\n            {1.00L, 1.00L},\n            {0.35L, 1.12L},\n        };\n\n        for (auto [alpha, gamma] : connectedParams) {\n            if (elapsed() > 1.05) break;\n            InitialState init = greedy_initial(alpha, gamma);\n            Candidate cand = make_candidate(init.P, init.B);\n            consider(cand, 3);\n        }\n\n        vector<char> allAllowed(N, 1);\n        vector<long double> globalGammas = {0.92L, 1.00L, 1.10L, 1.18L};\n\n        for (long double g : globalGammas) {\n            if (elapsed() > 1.45) break;\n            vector<int> P = greedy_on_allowed_gamma(allAllowed, g);\n            if (count_covered_by_P(P) < K) continue;\n            reduce_powers(P, allAllowed);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate cand = make_candidate(P, B);\n            consider(cand, 3);\n        }\n\n        // Fallback if somehow empty.\n        if (best.covered < 0) {\n            vector<int> P(N, 0);\n            vector<char> B(M, 0);\n            best = make_candidate(P, B);\n        }\n\n        if (elapsed() < 1.72) best = basic_improve(best, 2);\n        if (elapsed() < 1.86) best = local_remove(best);\n        if (elapsed() < HARD_LIMIT) best = basic_improve(best, 2);\n\n        return best;\n    }\n\n    void output(const Candidate& ans) const {\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans.P[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << int(ans.B[i]);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.input();\n    solver.precompute();\n    Candidate ans = solver.solve();\n    solver.output(ans);\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;\nusing ll = long long;\nusing Board = array<array<int, N>, N>;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    int E = 0;\n\n    long long score_like() const {\n        if ((int)ops.size() > 10000) return -(1LL << 60);\n        if (E == 0) return 100000LL - 5LL * (int)ops.size();\n        return 50000LL - 50LL * E;\n    }\n};\n\nint count_violations(const Board& a) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++E;\n            if (a[x][y] > a[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nBoard reflect_board(const Board& a) {\n    Board b{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            b[x][y] = a[x][x - y];\n        }\n    }\n    return b;\n}\n\nvector<Op> reflect_ops(vector<Op> ops) {\n    for (auto& op : ops) {\n        op.y1 = op.x1 - op.y1;\n        op.y2 = op.x2 - op.y2;\n    }\n    return ops;\n}\n\nbool better_candidate(const Candidate& a, const Candidate& b) {\n    if (a.score_like() != b.score_like()) return a.score_like() > b.score_like();\n    if (a.E != b.E) return a.E < b.E;\n    return a.ops.size() < b.ops.size();\n}\n\n/* ---------------- Previous constructive solver family ---------------- */\n\nstruct Builder {\n    Board a;\n    vector<Op> ops;\n\n    Builder(const Board& init) : a(init) {\n        ops.reserve(10000);\n    }\n\n    static bool reachable_down(int r, int c, int tr, int tc) {\n        if (r > tr) return false;\n        return (c <= tc && tc <= c + (tr - r));\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        swap(a[x1][y1], a[x2][y2]);\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    pair<int,int> find_min_subtriangle(int x, int y) const {\n        int best_v = INT_MAX;\n        pair<int,int> best = {x, y};\n        for (int i = x; i < N; ++i) {\n            int l = y;\n            int r = y + (i - x);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] < best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    pair<int,int> find_max_uppertriangle(int x, int y) const {\n        int best_v = -1;\n        pair<int,int> best = {x, y};\n        for (int i = 0; i <= x; ++i) {\n            int l = max(0, y - (x - i));\n            int r = min(i, y);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] > best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_best_path_top(int tx, int ty, int sx, int sy) const {\n        const int NEG = -1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                dp[i][j] = NEG;\n\n        dp[sx][sy] = 0;\n\n        for (int r = sx - 1; r >= tx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, sx, sy)) continue;\n                int best = NEG;\n                if (reachable_down(r + 1, c, sx, sy) && dp[r + 1][c] != NEG) {\n                    best = max(best, dp[r + 1][c]);\n                }\n                if (reachable_down(r + 1, c + 1, sx, sy) && dp[r + 1][c + 1] != NEG) {\n                    best = max(best, dp[r + 1][c + 1]);\n                }\n                if (best != NEG) dp[r][c] = a[r][c] + best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = tx, c = ty;\n        path.push_back({r, c});\n\n        while (!(r == sx && c == sy)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = NEG;\n\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, sx, sy)) return;\n                if (dp[nr][nc] == NEG) return;\n                if (nxt.first == -1 ||\n                    dp[nr][nc] > best ||\n                    (dp[nr][nc] == best && a[nr][nc] > a[nxt.first][nxt.second])) {\n                    best = dp[nr][nc];\n                    nxt = {nr, nc};\n                }\n            };\n\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back(nxt);\n        }\n\n        return path;\n    }\n\n    vector<pair<int,int>> build_best_path_bottom(int sx, int sy, int tx, int ty) const {\n        const int INF = 1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                dp[i][j] = INF;\n\n        dp[tx][ty] = 0;\n\n        for (int r = tx - 1; r >= sx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, tx, ty)) continue;\n                int best = INF;\n                if (reachable_down(r + 1, c, tx, ty) && dp[r + 1][c] != INF) {\n                    best = min(best, a[r + 1][c] + dp[r + 1][c]);\n                }\n                if (reachable_down(r + 1, c + 1, tx, ty) && dp[r + 1][c + 1] != INF) {\n                    best = min(best, a[r + 1][c + 1] + dp[r + 1][c + 1]);\n                }\n                dp[r][c] = best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = sx, c = sy;\n        path.push_back({r, c});\n\n        while (!(r == tx && c == ty)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = INF;\n\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, tx, ty)) return;\n                if (dp[nr][nc] == INF) return;\n                int cand = a[nr][nc] + dp[nr][nc];\n                if (nxt.first == -1 ||\n                    cand < best ||\n                    (cand == best && a[nr][nc] < a[nxt.first][nxt.second])) {\n                    best = cand;\n                    nxt = {nr, nc};\n                }\n            };\n\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back(nxt);\n        }\n\n        return path;\n    }\n\n    Candidate solve_topdown() {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_min_subtriangle(x, y);\n                auto path = build_best_path_top(x, y, sx, sy);\n                for (int i = (int)path.size() - 1; i >= 1; --i) {\n                    auto [x1, y1] = path[i];\n                    auto [x2, y2] = path[i - 1];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n\n    Candidate solve_bottomup() {\n        for (int x = N - 1; x >= 0; --x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_max_uppertriangle(x, y);\n                auto path = build_best_path_bottom(sx, sy, x, y);\n                for (int i = 1; i < (int)path.size(); ++i) {\n                    auto [x1, y1] = path[i - 1];\n                    auto [x2, y2] = path[i];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\n/* ---------------- New value-order solver family ---------------- */\n\nstruct ValueOrderSolver {\n    Board a;\n    array<int, M> posx{}, posy{};\n    vector<Op> ops;\n\n    ll W;\n    bool upward;\n    int curv = 0;\n\n    static constexpr ll INF = (1LL << 60);\n\n    ll memo[N][N];\n    bool seen[N][N];\n    int nxtx[N][N], nxty[N][N];\n\n    ValueOrderSolver(const Board& init, ll weight, bool up)\n        : a(init), W(weight), upward(up) {\n        ops.reserve(10000);\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                int v = a[x][y];\n                posx[v] = x;\n                posy[v] = y;\n            }\n        }\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        int v1 = a[x1][y1];\n        int v2 = a[x2][y2];\n        swap(a[x1][y1], a[x2][y2]);\n        posx[v1] = x2; posy[v1] = y2;\n        posx[v2] = x1; posy[v2] = y1;\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    ll dfs_up(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        int bestParVal = -1;\n\n        auto consider = [&](int px, int py) {\n            if (a[px][py] <= curv) return;\n            ll cand = dfs_up(px, py) + W - a[px][py];\n            int pval = a[px][py];\n            if (cand < best ||\n                (cand == best && (pval > bestParVal ||\n                                  (pval == bestParVal && py < by)))) {\n                best = cand;\n                bx = px; by = py;\n                bestParVal = pval;\n            }\n        };\n\n        if (x > 0) {\n            if (y > 0) consider(x - 1, y - 1);\n            if (y < x) consider(x - 1, y);\n        }\n\n        if (bx == -1) best = 0;\n\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    ll dfs_down(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        int bestChVal = INT_MAX;\n\n        auto consider = [&](int cx, int cy) {\n            if (a[cx][cy] >= curv) return;\n            ll cand = dfs_down(cx, cy) + W + a[cx][cy];\n            int cval = a[cx][cy];\n            if (cand < best ||\n                (cand == best && (cval < bestChVal ||\n                                  (cval == bestChVal && cy < by)))) {\n                best = cand;\n                bx = cx; by = cy;\n                bestChVal = cval;\n            }\n        };\n\n        if (x + 1 < N) {\n            consider(x + 1, y);\n            consider(x + 1, y + 1);\n        }\n\n        if (bx == -1) best = 0;\n\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    Candidate run() {\n        if (upward) {\n            for (int v = 0; v < M; ++v) {\n                curv = v;\n                memset(seen, 0, sizeof(seen));\n                int x = posx[v], y = posy[v];\n                dfs_up(x, y);\n                while (nxtx[x][y] != -1) {\n                    int nx = nxtx[x][y], ny = nxty[x][y];\n                    do_swap(x, y, nx, ny);\n                    x = nx; y = ny;\n                    if ((int)ops.size() > 10000) {\n                        return Candidate{ops, count_violations(a)};\n                    }\n                }\n            }\n        } else {\n            for (int v = M - 1; v >= 0; --v) {\n                curv = v;\n                memset(seen, 0, sizeof(seen));\n                int x = posx[v], y = posy[v];\n                dfs_down(x, y);\n                while (nxtx[x][y] != -1) {\n                    int nx = nxtx[x][y], ny = nxty[x][y];\n                    do_swap(x, y, nx, ny);\n                    x = nx; y = ny;\n                    if ((int)ops.size() > 10000) {\n                        return Candidate{ops, count_violations(a)};\n                    }\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\nCandidate solve_value_order(const Board& init, bool upward, ll W, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    ValueOrderSolver solver(b, W, upward);\n    Candidate c = solver.run();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nCandidate solve_builder_top(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_topdown();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nCandidate solve_builder_bottom(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_bottomup();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Board init{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n        }\n    }\n\n    vector<Candidate> cands;\n    cands.reserve(32);\n\n    // Safety baseline.\n    cands.push_back(Candidate{{}, count_violations(init)});\n\n    // New value-order candidates.\n    const vector<ll> weights = {\n        1000000000LL, // almost pure shortest path\n        700LL,\n        450LL,\n        300LL\n    };\n\n    for (ll W : weights) {\n        cands.push_back(solve_value_order(init, true,  W, false));\n        cands.push_back(solve_value_order(init, true,  W, true));\n        cands.push_back(solve_value_order(init, false, W, false));\n        cands.push_back(solve_value_order(init, false, W, true));\n    }\n\n    // Previous strong constructive family as fallback / extra diversity.\n    cands.push_back(solve_builder_top(init, false));\n    cands.push_back(solve_builder_top(init, true));\n    cands.push_back(solve_builder_bottom(init, false));\n    cands.push_back(solve_builder_bottom(init, true));\n\n    Candidate best = cands[0];\n    for (size_t i = 1; i < cands.size(); ++i) {\n        if (better_candidate(cands[i], best)) best = std::move(cands[i]);\n    }\n\n    if ((int)best.ops.size() > 10000) {\n        best.ops.clear();\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (auto &op : best.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick() : n(0) {}\n    Fenwick(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int r) const { // [0, r)\n        int s = 0;\n        for (; r > 0; r -= r & -r) s += bit[r];\n        return s;\n    }\n    int total() const { return sumPrefix(n); }\n};\n\nstruct Strategy {\n    int hmode; // peel-order heuristic\n    int smode; // choose mode\n};\n\nstruct PeelInfo {\n    array<int, 81> pos;\n    vector<int> safe0;\n};\n\nclass Solver {\n    static constexpr int V = 81;\n    int D, N, M;\n    int root;\n    array<char, V> obstacle{};\n    array<vector<int>, V> adj;\n    array<int, V> dist0{};\n    vector<int> cells; // non-obstacle, non-root cells\n\n    Strategy best_strategy{0, 0};\n    array<int, V> label{};\n\n    int id(int i, int j) const { return i * D + j; }\n\n    void build_adj() {\n        for (int v = 0; v < V; ++v) adj[v].clear();\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int u = id(i, j);\n                if (obstacle[u]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir], nj = j + dj[dir];\n                    if (ni < 0 || ni >= D || nj < 0 || nj >= D) continue;\n                    int v = id(ni, nj);\n                    if (obstacle[v]) continue;\n                    adj[u].push_back(v);\n                }\n            }\n        }\n    }\n\n    void bfs_dist(const array<char, V>& active, array<int, V>& dist) const {\n        dist.fill(-1);\n        queue<int> q;\n        if (!active[root]) return;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (!active[v] || dist[v] != -1) continue;\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n\n    void dfs_art(\n        int u, int p,\n        const array<char, V>& active,\n        array<int, V>& ord,\n        array<int, V>& low,\n        array<char, V>& arti,\n        int& timer\n    ) const {\n        ord[u] = low[u] = timer++;\n        int child = 0;\n        for (int v : adj[u]) {\n            if (!active[v]) continue;\n            if (ord[v] == -1) {\n                ++child;\n                dfs_art(v, u, active, ord, low, arti, timer);\n                low[u] = min(low[u], low[v]);\n                if (p != -1 && low[v] >= ord[u]) arti[u] = 1;\n            } else if (v != p) {\n                low[u] = min(low[u], ord[v]);\n            }\n        }\n        if (p == -1 && child > 1) arti[u] = 1;\n    }\n\n    void compute_articulation(const array<char, V>& active, array<char, V>& arti) const {\n        arti.fill(0);\n        array<int, V> ord, low;\n        ord.fill(-1);\n        low.fill(-1);\n        int timer = 0;\n        if (active[root]) dfs_art(root, -1, active, ord, low, arti, timer);\n    }\n\n    array<int, 4> make_key(\n        int v,\n        const array<int, V>& dist,\n        const array<int, V>& deg,\n        int hmode\n    ) const {\n        // Bigger key => removed earlier in canonical peel\n        if (hmode == 0) {\n            // Dynamic distance first\n            return {dist[v], -deg[v], dist0[v], -v};\n        } else if (hmode == 1) {\n            // Static distance first\n            return {dist0[v], -deg[v], dist[v], -v};\n        } else {\n            // Mixed\n            return {2 * dist[v] + dist0[v], -deg[v], dist[v], -v};\n        }\n    }\n\n    PeelInfo peel_info(const array<char, V>& occupied, const Strategy& st) const {\n        PeelInfo info;\n        info.pos.fill(-1);\n        info.safe0.clear();\n\n        array<char, V> active{};\n        active.fill(0);\n        active[root] = 1;\n        int rem = 0;\n        for (int v : cells) {\n            if (!occupied[v]) {\n                active[v] = 1;\n                ++rem;\n            }\n        }\n\n        for (int step = 0; step < rem; ++step) {\n            array<int, V> dist;\n            bfs_dist(active, dist);\n\n            array<char, V> arti;\n            compute_articulation(active, arti);\n\n            array<int, V> deg{};\n            deg.fill(0);\n            for (int u = 0; u < V; ++u) {\n                if (!active[u]) continue;\n                for (int v : adj[u]) if (active[v]) ++deg[u];\n            }\n\n            vector<int> safe;\n            int best = -1;\n            array<int, 4> bestKey{};\n\n            for (int v : cells) {\n                if (!active[v]) continue;\n                if (dist[v] == -1) continue; // should not happen\n                if (arti[v]) continue;\n                safe.push_back(v);\n                auto key = make_key(v, dist, deg, st.hmode);\n                if (best == -1 || key > bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n\n            if (step == 0) info.safe0 = safe;\n\n            if (best == -1) {\n                // Fallback; theoretically unnecessary\n                for (int v : cells) {\n                    if (active[v] && dist[v] != -1) {\n                        best = v;\n                        break;\n                    }\n                }\n                if (step == 0 && info.safe0.empty() && best != -1) {\n                    info.safe0.push_back(best);\n                }\n            }\n\n            if (best == -1) break;\n            info.pos[best] = step;\n            active[best] = 0;\n        }\n\n        return info;\n    }\n\n    int choose_cell(const array<char, V>& occupied, const Fenwick& unseen, int t, const Strategy& st) const {\n        int m = unseen.total();\n        int r = unseen.sumPrefix(t); // current label rank among unseen\n\n        PeelInfo info = peel_info(occupied, st);\n        vector<int> safe = info.safe0;\n\n        if (safe.empty()) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) if (!occupied[v]) return v;\n            return cells.front();\n        }\n\n        if (st.smode == 0) {\n            // Quantile among currently legal choices\n            sort(safe.begin(), safe.end(), [&](int a, int b) {\n                if (info.pos[a] != info.pos[b]) return info.pos[a] > info.pos[b];\n                return a < b;\n            });\n            int idx = (int)((long long)r * (int)safe.size() / m);\n            if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n            return safe[idx];\n        } else {\n            // Closest to absolute target position in canonical peel\n            int target = m - 1 - r; // large => early output\n            int best = -1;\n            pair<int, int> bestPair{INT_MAX, INT_MAX};\n            for (int v : safe) {\n                int d = abs(info.pos[v] - target);\n                int tie = (target * 2 >= m - 1) ? -info.pos[v] : info.pos[v];\n                pair<int, int> cur{d, tie};\n                if (best == -1 || cur < bestPair) {\n                    best = v;\n                    bestPair = cur;\n                }\n            }\n            return best;\n        }\n    }\n\n    int best_reachable_smallest(const array<char, V>& occ, const array<int, V>& lbl) const {\n        array<char, V> vis{};\n        vis.fill(0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n\n        int best = -1;\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (occ[v]) {\n                    if (best == -1 || lbl[v] < lbl[best]) best = v;\n                } else {\n                    if (!vis[v]) {\n                        vis[v] = 1;\n                        q.push(v);\n                    }\n                }\n            }\n        }\n\n        if (best == -1) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) {\n                if (occ[v] && (best == -1 || lbl[v] < lbl[best])) best = v;\n            }\n        }\n        return best;\n    }\n\n    long long simulate(const Strategy& st, const vector<int>& perm) const {\n        array<char, V> occ{};\n        occ.fill(0);\n        array<int, V> lbl;\n        lbl.fill(-1);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int x : perm) {\n            int c = choose_cell(occ, unseen, x, st);\n            occ[c] = 1;\n            lbl[c] = x;\n            unseen.add(x, -1);\n        }\n\n        array<char, V> curOcc = occ;\n        vector<int> out;\n        out.reserve(M);\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, lbl);\n            out.push_back(lbl[c]);\n            curOcc[c] = 0;\n        }\n\n        long long inv = 0;\n        for (int i = 0; i < M; ++i) {\n            for (int j = i + 1; j < M; ++j) {\n                if (out[i] > out[j]) ++inv;\n            }\n        }\n        return inv;\n    }\n\n    void train_best_strategy() {\n        vector<Strategy> cand = {\n            {0, 0}, {0, 1},\n            {1, 0}, {1, 1},\n            {2, 0}, {2, 1}\n        };\n\n        uint64_t seed = 1469598103934665603ULL;\n        seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n        for (int v = 0; v < V; ++v) {\n            if (obstacle[v]) {\n                seed ^= (uint64_t)(v + 1);\n                seed *= 1099511628211ULL;\n            }\n        }\n        mt19937_64 rng(seed);\n\n        const int TRAIN_ITERS = 4;\n        vector<vector<int>> perms(TRAIN_ITERS, vector<int>(M));\n        for (int it = 0; it < TRAIN_ITERS; ++it) {\n            iota(perms[it].begin(), perms[it].end(), 0);\n            shuffle(perms[it].begin(), perms[it].end(), rng);\n        }\n\n        long long bestScore = (1LL << 62);\n        for (const auto& st : cand) {\n            long long sumInv = 0;\n            for (int it = 0; it < TRAIN_ITERS; ++it) {\n                sumInv += simulate(st, perms[it]);\n            }\n            if (sumInv < bestScore) {\n                bestScore = sumInv;\n                best_strategy = st;\n            }\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> D >> N;\n        root = id(0, (D - 1) / 2);\n\n        obstacle.fill(0);\n        label.fill(-1);\n\n        for (int k = 0; k < N; ++k) {\n            int i, j;\n            cin >> i >> j;\n            obstacle[id(i, j)] = 1;\n        }\n\n        build_adj();\n\n        cells.clear();\n        for (int v = 0; v < V; ++v) {\n            if (!obstacle[v] && v != root) cells.push_back(v);\n        }\n        M = (int)cells.size();\n\n        // Original distances\n        array<char, V> active{};\n        active.fill(0);\n        for (int v = 0; v < V; ++v) if (!obstacle[v]) active[v] = 1;\n        bfs_dist(active, dist0);\n\n        train_best_strategy();\n\n        array<char, V> occupied{};\n        occupied.fill(0);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int d = 0; d < M; ++d) {\n            int t;\n            cin >> t;\n\n            int c = choose_cell(occupied, unseen, t, best_strategy);\n            occupied[c] = 1;\n            label[c] = t;\n            unseen.add(t, -1);\n\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            cout.flush();\n        }\n\n        array<char, V> curOcc = occupied;\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, label);\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            curOcc[c] = 0;\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXV = 2500;\nstatic constexpr int MAXC = 101;\n\nint n, m;\nbool origAdj[MAXC][MAXC];\nint distColor[MAXC];\nint degColor[MAXC];\nvector<vector<int>> depthGroups;\n\nstruct Board {\n    int h = 0, w = 0;\n    array<unsigned char, MAXV> a{};\n    int nonzero = 0;\n    long long distsum = 0;\n};\n\ninline bool better_board(const Board& x, const Board& y) {\n    if (x.nonzero != y.nonzero) return x.nonzero < y.nonzero;\n    if (x.distsum != y.distsum) return x.distsum < y.distsum;\n    return x.h * x.w < y.h * y.w;\n}\n\nvoid compute_stats(Board& b) {\n    b.nonzero = 0;\n    b.distsum = 0;\n    int V = b.h * b.w;\n    for (int i = 0; i < V; ++i) {\n        int c = b.a[i];\n        if (c != 0) ++b.nonzero;\n        b.distsum += distColor[c];\n    }\n}\n\ninline bool row_all_zero(const Board& b, int r) {\n    int base = r * b.w;\n    for (int j = 0; j < b.w; ++j) {\n        if (b.a[base + j] != 0) return false;\n    }\n    return true;\n}\n\ninline bool col_all_zero(const Board& b, int c) {\n    for (int i = 0; i < b.h; ++i) {\n        if (b.a[i * b.w + c] != 0) return false;\n    }\n    return true;\n}\n\nBoard delete_row_board(const Board& b, int r, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h - 1;\n    nb.w = b.w;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r) continue;\n        int base = i * b.w;\n        memcpy(&nb.a[p], &b.a[base], b.w * sizeof(unsigned char));\n        p += b.w;\n    }\n    return nb;\n}\n\nBoard delete_col_board(const Board& b, int c, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h;\n    nb.w = b.w - 1;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nvoid crop_zero_border(Board& b) {\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        while (b.h > 1 && row_all_zero(b, 0)) {\n            b = delete_row_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.h > 1 && row_all_zero(b, b.h - 1)) {\n            b = delete_row_board(b, b.h - 1, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, 0)) {\n            b = delete_col_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, b.w - 1)) {\n            b = delete_col_board(b, b.w - 1, 0, 0);\n            changed = true;\n        }\n    }\n}\n\nbool is_legal(const Board& b) {\n    static int cnt[MAXC], firstPos[MAXC];\n    static bool adj[MAXC][MAXC];\n    static int vis[MAXV];\n    static int q[MAXV];\n    static int vis0[(MAXN + 2) * (MAXN + 2)];\n\n    memset(cnt, 0, sizeof(cnt));\n    for (int i = 0; i < MAXC; ++i) firstPos[i] = -1;\n    memset(adj, 0, sizeof(adj));\n\n    int zeroCnt = 0;\n    int h = b.h, w = b.w;\n\n    for (int i = 0; i < h; ++i) {\n        int base = i * w;\n        for (int j = 0; j < w; ++j) {\n            int idx = base + j;\n            int c = b.a[idx];\n            if (c == 0) {\n                ++zeroCnt;\n            } else {\n                ++cnt[c];\n                if (firstPos[c] == -1) firstPos[c] = idx;\n            }\n\n            if ((i == 0 || i == h - 1 || j == 0 || j == w - 1) && c != 0) {\n                adj[c][0] = adj[0][c] = true;\n            }\n\n            if (i + 1 < h) {\n                int d = b.a[idx + w];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n            if (j + 1 < w) {\n                int d = b.a[idx + 1];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n        }\n    }\n\n    for (int c = 1; c <= m; ++c) {\n        if (cnt[c] == 0) return false;\n    }\n\n    for (int c = 0; c <= m; ++c) {\n        for (int d = 0; d <= m; ++d) {\n            if (adj[c][d] != origAdj[c][d]) return false;\n        }\n    }\n\n    memset(vis, 0, sizeof(vis));\n    int stamp = 1;\n\n    for (int color = 1; color <= m; ++color) {\n        int start = firstPos[color];\n        int ql = 0, qr = 0;\n        q[qr++] = start;\n        vis[start] = stamp;\n        int seen = 1;\n\n        while (ql < qr) {\n            int v = q[ql++];\n            int x = v / w, y = v % w;\n\n            if (x > 0) {\n                int to = v - w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    ++seen;\n                }\n            }\n            if (x + 1 < h) {\n                int to = v + w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    ++seen;\n                }\n            }\n            if (y > 0) {\n                int to = v - 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    ++seen;\n                }\n            }\n            if (y + 1 < w) {\n                int to = v + 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    ++seen;\n                }\n            }\n        }\n\n        if (seen != cnt[color]) return false;\n        ++stamp;\n    }\n\n    if (zeroCnt > 0) {\n        int H = h + 2, W = w + 2;\n        memset(vis0, 0, sizeof(vis0));\n        int ql = 0, qr = 0;\n        static int q2[(MAXN + 2) * (MAXN + 2)];\n        q2[qr++] = 0;\n        vis0[0] = 1;\n        int reachedZero = 0;\n\n        auto can_pass = [&](int r, int c) -> bool {\n            if (r < 0 || r >= H || c < 0 || c >= W) return false;\n            int id = r * W + c;\n            if (vis0[id]) return false;\n            if (r == 0 || r == H - 1 || c == 0 || c == W - 1) return true;\n            return b.a[(r - 1) * w + (c - 1)] == 0;\n        };\n\n        while (ql < qr) {\n            int v = q2[ql++];\n            int r = v / W, c = v % W;\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], nc = c + dc[k];\n                if (!can_pass(nr, nc)) continue;\n                int nid = nr * W + nc;\n                vis0[nid] = 1;\n                q2[qr++] = nid;\n                if (1 <= nr && nr <= h && 1 <= nc && nc <= w) {\n                    ++reachedZero;\n                }\n            }\n        }\n        if (reachedZero != zeroCnt) return false;\n    }\n\n    return true;\n}\n\nstruct DelCand {\n    Board nb;\n    int gainNz;\n    long long gainDist;\n};\n\nBoard shrink_pass(Board b, mt19937& rng, Clock::time_point deadline, int randomTopK) {\n    crop_zero_border(b);\n\n    while (Clock::now() < deadline) {\n        vector<DelCand> cands;\n        cands.reserve(b.h + b.w);\n\n        for (int r = 0; r < b.h; ++r) {\n            int gainNz = 0;\n            long long gainDist = 0;\n            int base = r * b.w;\n            for (int j = 0; j < b.w; ++j) {\n                int c = b.a[base + j];\n                if (c != 0) ++gainNz;\n                gainDist += distColor[c];\n            }\n            Board nb = delete_row_board(b, r, gainNz, gainDist);\n            crop_zero_border(nb);\n            if (is_legal(nb)) {\n                cands.push_back({nb, gainNz, gainDist});\n            }\n            if ((r & 7) == 0 && Clock::now() >= deadline) return b;\n        }\n\n        for (int c = 0; c < b.w; ++c) {\n            int gainNz = 0;\n            long long gainDist = 0;\n            for (int i = 0; i < b.h; ++i) {\n                int col = b.a[i * b.w + c];\n                if (col != 0) ++gainNz;\n                gainDist += distColor[col];\n            }\n            Board nb = delete_col_board(b, c, gainNz, gainDist);\n            crop_zero_border(nb);\n            if (is_legal(nb)) {\n                cands.push_back({nb, gainNz, gainDist});\n            }\n            if ((c & 7) == 0 && Clock::now() >= deadline) return b;\n        }\n\n        if (cands.empty()) break;\n\n        sort(cands.begin(), cands.end(), [](const DelCand& x, const DelCand& y) {\n            if (x.gainNz != y.gainNz) return x.gainNz > y.gainNz;\n            if (x.gainDist != y.gainDist) return x.gainDist > y.gainDist;\n            return better_board(x.nb, y.nb);\n        });\n\n        if (cands[0].gainNz <= 0) break;\n\n        int lim = 1;\n        while (lim < (int)cands.size() && lim < randomTopK && cands[lim].gainNz == cands[0].gainNz) {\n            ++lim;\n        }\n        int pick = 0;\n        if (lim > 1) {\n            pick = uniform_int_distribution<int>(0, lim - 1)(rng);\n        }\n        b = cands[pick].nb;\n        crop_zero_border(b);\n    }\n\n    return b;\n}\n\nstruct LSState {\n    int h = 0, w = 0, V = 0;\n    array<unsigned char, MAXV> g{};\n    array<int, MAXC> cnt{};\n    int edge[MAXC][MAXC];\n    long long distSum = 0;\n    int nonzero = 0;\n\n    array<array<short, 4>, MAXV> nbr{};\n    array<unsigned char, MAXV> nbrCnt{};\n    array<unsigned char, MAXV> bside{};\n};\n\nLSState build_state(const Board& b) {\n    LSState st;\n    st.h = b.h;\n    st.w = b.w;\n    st.V = b.h * b.w;\n    st.cnt.fill(0);\n    memset(st.edge, 0, sizeof(st.edge));\n    st.distSum = 0;\n    st.nonzero = 0;\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = b.a[idx];\n        st.g[idx] = b.a[idx];\n        ++st.cnt[c];\n        st.distSum += distColor[c];\n        if (c != 0) ++st.nonzero;\n    }\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int i = idx / st.w, j = idx % st.w;\n        int k = 0;\n        if (i > 0) st.nbr[idx][k++] = idx - st.w;\n        if (i + 1 < st.h) st.nbr[idx][k++] = idx + st.w;\n        if (j > 0) st.nbr[idx][k++] = idx - 1;\n        if (j + 1 < st.w) st.nbr[idx][k++] = idx + 1;\n        st.nbrCnt[idx] = (unsigned char)k;\n        st.bside[idx] = (unsigned char)((i == 0) + (i == st.h - 1) + (j == 0) + (j == st.w - 1));\n    }\n\n    auto add_edge = [&](int a, int b, int delta) {\n        if (a == b) return;\n        st.edge[a][b] += delta;\n        st.edge[b][a] += delta;\n    };\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = st.g[idx];\n        int i = idx / st.w, j = idx % st.w;\n        if (i == 0) add_edge(c, 0, 1);\n        if (i == st.h - 1) add_edge(c, 0, 1);\n        if (j == 0) add_edge(c, 0, 1);\n        if (j == st.w - 1) add_edge(c, 0, 1);\n\n        if (i + 1 < st.h) add_edge(c, st.g[idx + st.w], 1);\n        if (j + 1 < st.w) add_edge(c, st.g[idx + 1], 1);\n    }\n\n    return st;\n}\n\nstatic int conn_vis[MAXV];\nstatic int conn_stamp = 1;\n\nbool connected_after_remove(const LSState& st, int color, int remIdx, int need, int startIdx) {\n    ++conn_stamp;\n    if (conn_stamp == INT_MAX) {\n        memset(conn_vis, 0, sizeof(conn_vis));\n        conn_stamp = 1;\n    }\n\n    static int q[MAXV];\n    int ql = 0, qr = 0;\n    q[qr++] = startIdx;\n    conn_vis[startIdx] = conn_stamp;\n    int seen = 1;\n\n    while (ql < qr) {\n        int v = q[ql++];\n        int deg = st.nbrCnt[v];\n        for (int k = 0; k < deg; ++k) {\n            int to = st.nbr[v][k];\n            if (to == remIdx) continue;\n            if (st.g[to] != color) continue;\n            if (conn_vis[to] == conn_stamp) continue;\n            conn_vis[to] = conn_stamp;\n            q[qr++] = to;\n            ++seen;\n            if (seen == need) return true;\n        }\n    }\n    return seen == need;\n}\n\nbool try_move(LSState& st, int idx, int t) {\n    int c = st.g[idx];\n    if (c == 0 || c == t) return false;\n    if (st.cnt[c] <= 1) return false;\n\n    int sameNbr = 0;\n    int startIdx = -1;\n    bool targetConnected = false;\n\n    if (t == 0 && st.bside[idx] > 0) targetConnected = true;\n\n    int pa[12], pb[12], pd[12];\n    int pnum = 0;\n\n    auto add_change = [&](int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < pnum; ++i) {\n            if (pa[i] == a && pb[i] == b) {\n                pd[i] += d;\n                return;\n            }\n        }\n        pa[pnum] = a;\n        pb[pnum] = b;\n        pd[pnum] = d;\n        ++pnum;\n    };\n\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        int to = st.nbr[idx][k];\n        int d = st.g[to];\n        if (d == c) {\n            ++sameNbr;\n            startIdx = to;\n        }\n        if (d == t) targetConnected = true;\n        if (t == 0 && d == 0) targetConnected = true;\n\n        if (c != d) add_change(c, d, -1);\n        if (t != d) add_change(t, d, +1);\n    }\n\n    if (st.bside[idx] > 0) {\n        add_change(c, 0, -st.bside[idx]);\n        add_change(t, 0, +st.bside[idx]);\n    }\n\n    if (!targetConnected) return false;\n    if (sameNbr == 0) return false;\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        int nc = st.edge[a][b] + pd[i];\n        if (nc < 0) return false;\n        bool nadj = (nc > 0);\n        if (nadj != origAdj[a][b]) return false;\n    }\n\n    if (sameNbr >= 2) {\n        if (!connected_after_remove(st, c, idx, st.cnt[c] - 1, startIdx)) return false;\n    }\n\n    st.g[idx] = (unsigned char)t;\n    --st.cnt[c];\n    ++st.cnt[t];\n    st.distSum += (long long)distColor[t] - distColor[c];\n    if (t == 0) --st.nonzero;\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        st.edge[a][b] += pd[i];\n        st.edge[b][a] += pd[i];\n    }\n\n    return true;\n}\n\narray<int, MAXC> make_key(const LSState& st, mt19937& rng) {\n    array<int, MAXC> key{};\n    key.fill(0);\n    key[0] = 0;\n\n    for (int d = 1; d < (int)depthGroups.size(); ++d) {\n        vector<int> v = depthGroups[d];\n        shuffle(v.begin(), v.end(), rng);\n        stable_sort(v.begin(), v.end(), [&](int a, int b) {\n            if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n            if (degColor[a] != degColor[b]) return degColor[a] > degColor[b];\n            return a < b;\n        });\n        for (int i = 0; i < (int)v.size(); ++i) {\n            key[v[i]] = d * 1000 + (i + 1);\n        }\n    }\n    return key;\n}\n\nvoid optimize(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    vector<int> ord(st.V);\n    iota(ord.begin(), ord.end(), 0);\n\n    int noMoveRounds = 0;\n    while (Clock::now() < deadline && noMoveRounds < 4) {\n        auto key = make_key(st, rng);\n        shuffle(ord.begin(), ord.end(), rng);\n        stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return key[st.g[a]] > key[st.g[b]];\n        });\n\n        bool moved = false;\n\n        for (int it = 0; it < st.V; ++it) {\n            if ((it & 255) == 0 && Clock::now() >= deadline) return;\n\n            int idx = ord[it];\n            int c = st.g[idx];\n            if (c == 0) continue;\n\n            int cand[5];\n            int ccnt = 0;\n\n            auto add_cand = [&](int x) {\n                if (x == c) return;\n                if (key[x] >= key[c]) return;\n                for (int i = 0; i < ccnt; ++i) if (cand[i] == x) return;\n                cand[ccnt++] = x;\n            };\n\n            if (st.bside[idx] > 0) add_cand(0);\n            int deg = st.nbrCnt[idx];\n            for (int k = 0; k < deg; ++k) add_cand(st.g[st.nbr[idx][k]]);\n\n            sort(cand, cand + ccnt, [&](int a, int b) {\n                if (key[a] != key[b]) return key[a] < key[b];\n                return a < b;\n            });\n\n            for (int i = 0; i < ccnt; ++i) {\n                if (try_move(st, idx, cand[i])) {\n                    moved = true;\n                    break;\n                }\n            }\n        }\n\n        if (moved) noMoveRounds = 0;\n        else ++noMoveRounds;\n    }\n}\n\nBoard state_to_board(const LSState& st) {\n    Board b;\n    b.h = st.h;\n    b.w = st.w;\n    b.nonzero = st.nonzero;\n    b.distsum = st.distSum;\n    for (int i = 0; i < st.V; ++i) b.a[i] = st.g[i];\n    return b;\n}\n\nBoard shave_pass(Board b, mt19937& rng, Clock::time_point deadline) {\n    crop_zero_border(b);\n    if (Clock::now() >= deadline) return b;\n    LSState st = build_state(b);\n    optimize(st, rng, deadline);\n    Board nb = state_to_board(st);\n    crop_zero_border(nb);\n    return nb;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n >> m;\n    Board original;\n    original.h = n;\n    original.w = n;\n    for (int i = 0; i < n * n; ++i) {\n        int x;\n        cin >> x;\n        original.a[i] = (unsigned char)x;\n    }\n\n    memset(origAdj, 0, sizeof(origAdj));\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int idx = i * n + j;\n            int c = original.a[idx];\n            if (i == 0 || i == n - 1 || j == 0 || j == n - 1) {\n                origAdj[c][0] = origAdj[0][c] = true;\n            }\n            if (i + 1 < n) {\n                int d = original.a[idx + n];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n            if (j + 1 < n) {\n                int d = original.a[idx + 1];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n        }\n    }\n\n    const int INF = 1e9;\n    for (int i = 0; i <= m; ++i) distColor[i] = INF;\n    queue<int> q;\n    distColor[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (int to = 0; to <= m; ++to) {\n            if (!origAdj[v][to]) continue;\n            if (distColor[to] != INF) continue;\n            distColor[to] = distColor[v] + 1;\n            q.push(to);\n        }\n    }\n\n    for (int i = 0; i <= m; ++i) {\n        int dg = 0;\n        for (int j = 0; j <= m; ++j) if (origAdj[i][j]) ++dg;\n        degColor[i] = dg;\n    }\n\n    int maxDepth = 0;\n    for (int c = 1; c <= m; ++c) maxDepth = max(maxDepth, distColor[c]);\n    depthGroups.assign(maxDepth + 1, {});\n    for (int c = 1; c <= m; ++c) depthGroups[distColor[c]].push_back(c);\n\n    compute_stats(original);\n\n    mt19937 rng(123456789);\n    auto start = Clock::now();\n    auto deadline = start + chrono::milliseconds(1900);\n\n    auto sub_deadline = [&](int ms) {\n        auto now = Clock::now();\n        auto t = now + chrono::milliseconds(ms);\n        return min(t, deadline);\n    };\n\n    Board best = original;\n    Board cur = original;\n\n    // Initial macro compression: deterministic + randomized.\n    if (Clock::now() < deadline) {\n        Board b1 = shrink_pass(original, rng, sub_deadline(180), 1);\n        if (better_board(b1, best)) best = b1;\n        Board b2 = shrink_pass(original, rng, sub_deadline(180), 4);\n        if (better_board(b2, best)) best = b2;\n        cur = better_board(b1, b2) ? b1 : b2;\n        if (better_board(best, cur)) cur = best;\n    }\n\n    while (Clock::now() < deadline) {\n        Board s1 = shave_pass(cur, rng, sub_deadline(220));\n        if (better_board(s1, cur)) cur = s1;\n        if (better_board(cur, best)) best = cur;\n\n        if (Clock::now() >= deadline) break;\n\n        Board s2 = shrink_pass(cur, rng, sub_deadline(120), 3);\n        if (better_board(s2, cur)) cur = s2;\n        if (better_board(cur, best)) best = cur;\n\n        if (Clock::now() + chrono::milliseconds(260) < deadline) {\n            Board alt = shrink_pass(original, rng, sub_deadline(90), 5);\n            if (better_board(alt, best) || alt.nonzero <= best.nonzero + 40) {\n                alt = shave_pass(alt, rng, sub_deadline(140));\n                if (better_board(alt, best)) {\n                    best = alt;\n                    cur = alt;\n                }\n            }\n        } else {\n            cur = best;\n        }\n    }\n\n    crop_zero_border(best);\n\n    vector<vector<int>> out(n, vector<int>(n, 0));\n    for (int i = 0; i < best.h; ++i) {\n        for (int j = 0; j < best.w; ++j) {\n            out[i][j] = best.a[i * best.w + j];\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << out[i][j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n\n    vector<int> cost_ins;                    // upper bound for binary insertion sort cost\n    vector<vector<signed char>> itemMemo;    // item pair comparison cache\n    vector<vector<signed char>> blockMemo;   // block comparison cache\n\n    vector<vector<int>> blocks;\n    vector<vector<int>> bins;\n\n    vector<int> order_est;   // estimated descending order (heavy -> light)\n    vector<int> rank_pos;    // estimated rank position for each item\n    vector<double> pweight;  // pseudo weight from estimated rank\n    vector<double> est_load; // estimated bin loads\n    vector<double> harm;     // harmonic numbers\n\n    int M = 1;\n    int baseSize = 1;\n    int remBlocks = 0;\n    int iterBound = 0;\n    int reserve_balance = 0;\n\n    static signed char enc(char c) {\n        if (c == '>') return 1;\n        if (c == '<') return -1;\n        return 2;\n    }\n    static char dec(signed char v) {\n        if (v == 1) return '>';\n        if (v == -1) return '<';\n        return '=';\n    }\n    static char rev(char c) {\n        if (c == '>') return '<';\n        if (c == '<') return '>';\n        return '=';\n    }\n\n    int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 0, y = 1;\n        while (y < x) y <<= 1, ++p;\n        return p;\n    }\n\n    char ask_sets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) {\n            // Should never happen.\n            exit(0);\n        }\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        ++used;\n        return s[0];\n    }\n\n    char cmp_item(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = itemMemo[a][b];\n        if (m != 0) return dec(m);\n        char s = ask_sets(vector<int>{a}, vector<int>{b});\n        itemMemo[a][b] = enc(s);\n        itemMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    char cmp_block(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = blockMemo[a][b];\n        if (m != 0) return dec(m);\n\n        vector<int> L, R;\n        L.reserve(baseSize);\n        R.reserve(baseSize);\n        for (int i = 0; i < baseSize; ++i) L.push_back(blocks[a][i]);\n        for (int i = 0; i < baseSize; ++i) R.push_back(blocks[b][i]);\n\n        char s = ask_sets(L, R);\n        blockMemo[a][b] = enc(s);\n        blockMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    void precompute_costs() {\n        cost_ins.assign(N + 1, 0);\n        for (int n = 1; n <= N; ++n) {\n            cost_ins[n] = cost_ins[n - 1] + ceil_log2_int(n);\n        }\n\n        harm.assign(N + 1, 0.0);\n        for (int i = 1; i <= N; ++i) harm[i] = harm[i - 1] + 1.0 / i;\n    }\n\n    int scheme_cost(int m) {\n        int base = N / m;\n        int rem = N % m;\n        long long c = 1LL * rem * cost_ins[base + 1]\n                    + 1LL * (m - rem) * cost_ins[base]\n                    + cost_ins[m];\n        return (int)c;\n    }\n\n    void choose_scheme() {\n        iterBound = 2 * (D - 1) + 6 + 2 * ceil_log2_int(N);\n        reserve_balance = min(Q, 2 * iterBound);\n\n        double bestScore = -1e100;\n        int bestM = 1;\n\n        for (int m = 1; m <= N; ++m) {\n            int c = scheme_cost(m);\n            if (c > Q) continue;\n            int extra = max(0, Q - c - reserve_balance);\n            double place_cnt = 0.0;\n            if (D > 1) {\n                place_cnt = min<double>(N - D, extra / double(D - 1));\n            }\n            double score = m + 0.8 * place_cnt;\n            if (score > bestScore + 1e-12 || (abs(score - bestScore) <= 1e-12 && m > bestM)) {\n                bestScore = score;\n                bestM = m;\n            }\n        }\n\n        M = bestM;\n        baseSize = N / M;\n        remBlocks = N % M;\n    }\n\n    vector<int> sort_items_by_weight(const vector<int>& arr) {\n        vector<int> res;\n        res.reserve(arr.size());\n        for (int x : arr) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_item(x, res[mid]); // '>' => x heavier\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, x);\n        }\n        return res;\n    }\n\n    vector<int> sort_block_ids(const vector<int>& ids) {\n        vector<int> res;\n        res.reserve(ids.size());\n        for (int id : ids) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_block(id, res[mid]); // '>' => id heavier\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, id);\n        }\n        return res;\n    }\n\n    void build_estimated_order() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n\n        blocks.clear();\n        int cur = 0;\n        for (int i = 0; i < M; ++i) {\n            int sz = baseSize + (i < remBlocks ? 1 : 0);\n            vector<int> blk;\n            blk.reserve(sz);\n            for (int j = 0; j < sz; ++j) blk.push_back(items[cur++]);\n            blocks.push_back(sort_items_by_weight(blk));\n        }\n\n        blockMemo.assign(M, vector<signed char>(M, 0));\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        ids = sort_block_ids(ids);\n\n        order_est.clear();\n        order_est.reserve(N);\n        for (int id : ids) {\n            for (int x : blocks[id]) order_est.push_back(x);\n        }\n\n        rank_pos.assign(N, 0);\n        pweight.assign(N, 0.0);\n        for (int pos = 0; pos < N; ++pos) {\n            int x = order_est[pos];\n            rank_pos[x] = pos;\n            pweight[x] = harm[N] - harm[pos]; // expected weight of pos-th largest (up to scale)\n        }\n    }\n\n    int actual_lightest_bin_simple() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            char s = ask_sets(bins[i], bins[best]);\n            if (s == '<') best = i;\n        }\n        return best;\n    }\n\n    int pseudo_lightest_bin() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            if (est_load[i] < est_load[best] - 1e-12) best = i;\n            else if (abs(est_load[i] - est_load[best]) <= 1e-12) {\n                if (bins[i].size() < bins[best].size()) best = i;\n                else if (bins[i].size() == bins[best].size() && i < best) best = i;\n            }\n        }\n        return best;\n    }\n\n    void insert_sorted_bin(int b, int item) {\n        auto &v = bins[b];\n        int rk = rank_pos[item];\n        auto it = lower_bound(v.begin(), v.end(), rk,\n                              [&](int lhs_item, int rhs_rank) {\n                                  return rank_pos[lhs_item] < rhs_rank;\n                              });\n        v.insert(it, item);\n    }\n\n    void assign_initial() {\n        bins.assign(D, {});\n        est_load.assign(D, 0.0);\n\n        for (int i = 0; i < N; ++i) {\n            int x = order_est[i];\n            int b;\n            if (i < D) {\n                b = i; // ensure all nonempty\n            } else if (used + (D - 1) + reserve_balance <= Q) {\n                b = actual_lightest_bin_simple();\n            } else {\n                b = pseudo_lightest_bin();\n            }\n            bins[b].push_back(x); // order_est is descending, so push_back keeps bin sorted\n            est_load[b] += pweight[x];\n        }\n    }\n\n    void pseudo_improve() {\n        for (int iter = 0; iter < 2000; ++iter) {\n            int h = 0, l = 0;\n            for (int i = 1; i < D; ++i) {\n                if (est_load[i] > est_load[h]) h = i;\n                if (est_load[i] < est_load[l]) l = i;\n            }\n            if (h == l) break;\n\n            double lh = est_load[h], ll = est_load[l];\n            double bestDelta = -1e-12;\n            int bestType = 0; // 1 move, 2 swap\n            int bestI = -1, bestJ = -1;\n\n            if ((int)bins[h].size() > 1) {\n                for (int i = 0; i < (int)bins[h].size(); ++i) {\n                    int x = bins[h][i];\n                    double w = pweight[x];\n                    double nh = lh - w;\n                    double nl = ll + w;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 1;\n                        bestI = i;\n                    }\n                }\n            }\n\n            for (int i = 0; i < (int)bins[h].size(); ++i) {\n                int x = bins[h][i];\n                double wx = pweight[x];\n                for (int j = 0; j < (int)bins[l].size(); ++j) {\n                    int y = bins[l][j];\n                    double wy = pweight[y];\n                    double nh = lh - wx + wy;\n                    double nl = ll - wy + wx;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 2;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestType == 0) break;\n\n            if (bestType == 1) {\n                int x = bins[h][bestI];\n                bins[h].erase(bins[h].begin() + bestI);\n                insert_sorted_bin(l, x);\n                est_load[h] -= pweight[x];\n                est_load[l] += pweight[x];\n            } else {\n                int x = bins[h][bestI];\n                int y = bins[l][bestJ];\n                bins[h].erase(bins[h].begin() + bestI);\n                bins[l].erase(bins[l].begin() + bestJ);\n                insert_sorted_bin(h, y);\n                insert_sorted_bin(l, x);\n                est_load[h] += pweight[y] - pweight[x];\n                est_load[l] += pweight[x] - pweight[y];\n            }\n        }\n    }\n\n    pair<int, int> actual_extremes() {\n        vector<vector<signed char>> memo(D, vector<signed char>(D, 0));\n        auto cmpBin = [&](int a, int b) -> char {\n            if (a == b) return '=';\n            signed char &m = memo[a][b];\n            if (m != 0) return dec(m);\n            char s = ask_sets(bins[a], bins[b]);\n            memo[a][b] = enc(s);\n            memo[b][a] = enc(rev(s));\n            return s;\n        };\n\n        int hi = 0, lo = 0;\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, hi) == '>') hi = i;\n        }\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, lo) == '<') lo = i;\n        }\n        return {hi, lo};\n    }\n\n    int select_move_candidate(int H, int L) {\n        int m = (int)bins[H].size();\n        if (m <= 1) return -1;\n\n        vector<signed char> memo(m, 0);\n        auto test = [&](int idx) -> char {\n            if (memo[idx] != 0) return dec(memo[idx]);\n            vector<int> left, right;\n            left.reserve(m - 1);\n            right.reserve(bins[L].size() + 1);\n            for (int i = 0; i < m; ++i) if (i != idx) left.push_back(bins[H][i]);\n            for (int x : bins[L]) right.push_back(x);\n            right.push_back(bins[H][idx]);\n            char s = ask_sets(left, right);\n            memo[idx] = enc(s);\n            return s;\n        };\n\n        char s0 = test(0);\n        if (s0 == '>' || s0 == '=') return 0;\n\n        char sl = test(m - 1);\n        if (sl == '=') return m - 1;\n        if (sl == '<') return -1; // even moving the lightest item overcompensates\n\n        int lo = 0, hi = m - 1; // test(lo) == '<', test(hi) == '>'\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '<') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double v1 = fabs(diff - 2.0 * pweight[bins[H][lo]]);\n        double v2 = fabs(diff - 2.0 * pweight[bins[H][hi]]);\n        return (v2 < v1 ? hi : lo);\n    }\n\n    int select_swap_candidate(int H, int L) {\n        int xidx = (int)bins[H].size() - 1; // lightest item in heavy bin\n        int x = bins[H][xidx];\n        int rkx = rank_pos[x];\n\n        int n = (int)bins[L].size();\n        int first = 0;\n        while (first < n && rank_pos[bins[L][first]] < rkx) ++first; // first estimated-lighter-than-x\n        if (first == n) return -1;\n\n        vector<signed char> memo(n, 0);\n        auto test = [&](int yidx) -> char {\n            if (memo[yidx] != 0) return dec(memo[yidx]);\n            vector<int> left, right;\n            left.reserve(bins[H].size());\n            right.reserve(bins[L].size());\n            for (int i = 0; i < (int)bins[H].size(); ++i) {\n                if (i != xidx) left.push_back(bins[H][i]);\n            }\n            left.push_back(bins[L][yidx]);\n\n            for (int i = 0; i < (int)bins[L].size(); ++i) {\n                if (i != yidx) right.push_back(bins[L][i]);\n            }\n            right.push_back(x);\n\n            char s = ask_sets(left, right);\n            memo[yidx] = enc(s);\n            return s;\n        };\n\n        char sf = test(first);\n        if (sf == '=') return first;\n        if (sf == '<') return -1; // even the smallest transfer overcompensates\n\n        char sl = test(n - 1);\n        if (sl == '=') return n - 1;\n        if (sl == '>') return n - 1; // even the largest transfer is still not enough\n\n        int lo = first, hi = n - 1; // test(lo) == '>', test(hi) == '<'\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '>') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double wx = pweight[x];\n        double d1 = fabs(diff - 2.0 * (wx - pweight[bins[L][lo]]));\n        double d2 = fabs(diff - 2.0 * (wx - pweight[bins[L][hi]]));\n        return (d2 < d1 ? hi : lo);\n    }\n\n    void apply_move(int H, int L, int idx) {\n        int x = bins[H][idx];\n        bins[H].erase(bins[H].begin() + idx);\n        insert_sorted_bin(L, x);\n        est_load[H] -= pweight[x];\n        est_load[L] += pweight[x];\n    }\n\n    void apply_swap(int H, int L, int yidx) {\n        int xidx = (int)bins[H].size() - 1;\n        int x = bins[H][xidx];\n        int y = bins[L][yidx];\n\n        bins[H].erase(bins[H].begin() + xidx);\n        bins[L].erase(bins[L].begin() + yidx);\n        insert_sorted_bin(H, y);\n        insert_sorted_bin(L, x);\n\n        est_load[H] += pweight[y] - pweight[x];\n        est_load[L] += pweight[x] - pweight[y];\n    }\n\n    void actual_improve() {\n        while (used + iterBound <= Q) {\n            auto [H, L] = actual_extremes();\n            if (H == L) break;\n\n            bool changed = false;\n\n            if ((int)bins[H].size() > 1) {\n                int idx = select_move_candidate(H, L);\n                if (idx != -1) {\n                    apply_move(H, L, idx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) {\n                int yidx = select_swap_candidate(H, L);\n                if (yidx != -1) {\n                    apply_swap(H, L, yidx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void fill_dummy_queries() {\n        while (used < Q) {\n            ask_sets(vector<int>{0}, vector<int>{1});\n        }\n    }\n\n    void output_answer() {\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b]) ans[x] = b;\n        }\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        itemMemo.assign(N, vector<signed char>(N, 0));\n\n        precompute_costs();\n        choose_scheme();\n        build_estimated_order();\n        assign_initial();\n        pseudo_improve();\n        actual_improve();\n        fill_dummy_queries();\n        output_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NMAX = 200;\nstatic constexpr int MMAX = 10;\nstatic constexpr uint8_t REMOVED = 255;\nstatic constexpr int INF = 1e9;\n\nint N, M;\n\nstruct State {\n    uint16_t a[MMAX][NMAX]; // bottom -> top\n    uint8_t h[MMAX];\n    uint8_t st_of[NMAX + 1]; // stack id, or 255 if removed\n    uint8_t pos[NMAX + 1];   // position in stack\n    uint16_t cur;            // next box to remove\n};\n\nstruct Result {\n    int energy = INF;\n    vector<pair<int,int>> ops;\n};\n\nstruct Features {\n    int solo = 0;     // optimistic exact cost if moved blockers disappear\n    int bad = 0;      // non-record-minima from bottom\n    int seg = 0;      // number of forced future expensive moves in solo model\n    int empty = 0;\n};\n\nstruct Node {\n    State st;\n    int g;            // exact energy so far\n    int parent;       // index in nodes, -1 for root\n    uint8_t actionTo; // 1..M, 0 for root\n};\n\nstruct TempChild {\n    State st;\n    int g;\n    int hval;\n    int eval;\n    int parent;\n    uint8_t actionTo;\n    uint16_t cur;\n};\n\nstruct Config {\n    int width;\n    int mode;\n    int greedyDepth;\n};\n\nstatic auto global_start = chrono::steady_clock::now();\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n}\n\ninline void pop_all(State& st, vector<pair<int,int>>* ops = nullptr) {\n    while (st.cur <= N) {\n        uint8_t s = st.st_of[st.cur];\n        if (s == REMOVED) {\n            ++st.cur;\n            continue;\n        }\n        if ((int)st.pos[st.cur] + 1 != (int)st.h[s]) break;\n        if (ops) ops->push_back({st.cur, 0});\n        --st.h[s];\n        st.st_of[st.cur] = REMOVED;\n        ++st.cur;\n    }\n}\n\ninline int move_blockers(State& st, int dst) {\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    int start = p + 1;\n    int len = (int)st.h[s] - start;\n    for (int i = start; i < (int)st.h[s]; ++i) {\n        uint16_t x = st.a[s][i];\n        st.a[dst][st.h[dst]] = x;\n        st.st_of[x] = (uint8_t)dst;\n        st.pos[x] = st.h[dst];\n        ++st.h[dst];\n    }\n    st.h[s] = (uint8_t)start;\n    return len;\n}\n\ninline Features calc_features(const State& st) {\n    Features f;\n    int recPos[NMAX];\n\n    for (int i = 0; i < M; ++i) {\n        int h = st.h[i];\n        if (h == 0) {\n            ++f.empty;\n            continue;\n        }\n\n        int rc = 0;\n        int mn = N + 1;\n        for (int j = 0; j < h; ++j) {\n            int x = st.a[i][j];\n            if (x < mn) {\n                mn = x;\n                recPos[rc++] = j;\n            }\n        }\n\n        f.bad += h - rc;\n\n        for (int k = rc - 1; k >= 0; --k) {\n            int end = (k + 1 < rc ? recPos[k + 1] - 1 : h - 1);\n            int above = end - recPos[k];\n            if (above > 0) {\n                f.solo += above + 1;\n                ++f.seg;\n            }\n        }\n    }\n    return f;\n}\n\ninline int estimate(const State& st, int mode) {\n    Features f = calc_features(st);\n    switch (mode) {\n        case 0: return f.solo;\n        case 1: return f.solo + f.bad;\n        case 2: return f.solo + 2 * f.bad;\n        case 3: return f.solo + f.bad + f.seg;\n        default: return f.solo;\n    }\n}\n\nint lookahead_cost(const State& st, int depth, int mode) {\n    if (st.cur > N) return 0;\n    if (depth == 0) return estimate(st, mode);\n\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    if (p + 1 >= (int)st.h[s]) {\n        State nx = st;\n        pop_all(nx, nullptr);\n        return lookahead_cost(nx, depth, mode);\n    }\n\n    int len = (int)st.h[s] - p - 1;\n    int best = INF;\n\n    for (int dst = 0; dst < M; ++dst) {\n        if (dst == s) continue;\n        State nx = st;\n        move_blockers(nx, dst);\n        pop_all(nx, nullptr);\n        best = min(best, len + 1 + lookahead_cost(nx, depth - 1, mode));\n    }\n    return best;\n}\n\nResult greedy_complete(State st, int mode, int depth) {\n    Result res;\n    res.energy = 0;\n\n    while (st.cur <= N) {\n        int cur = st.cur;\n        int s = st.st_of[cur];\n        int p = st.pos[cur];\n\n        if (p + 1 >= (int)st.h[s]) {\n            pop_all(st, &res.ops);\n            continue;\n        }\n\n        int len = (int)st.h[s] - p - 1;\n        int v = st.a[s][p + 1];\n\n        int bestDst = -1;\n        int bestVal = INF;\n        int bestCur = -1;\n        int bestH = INF;\n\n        for (int dst = 0; dst < M; ++dst) {\n            if (dst == s) continue;\n            State nx = st;\n            move_blockers(nx, dst);\n            pop_all(nx, nullptr);\n            int hval = estimate(nx, mode);\n            int val = len + 1 + (depth > 1 ? lookahead_cost(nx, depth - 1, mode) : hval);\n\n            if (val < bestVal ||\n                (val == bestVal && nx.cur > bestCur) ||\n                (val == bestVal && nx.cur == bestCur && hval < bestH) ||\n                (val == bestVal && nx.cur == bestCur && hval == bestH && dst < bestDst)) {\n                bestVal = val;\n                bestDst = dst;\n                bestCur = nx.cur;\n                bestH = hval;\n            }\n        }\n\n        res.ops.push_back({v, bestDst + 1});\n        res.energy += len + 1;\n        move_blockers(st, bestDst);\n        pop_all(st, &res.ops);\n    }\n\n    return res;\n}\n\nvector<uint8_t> collect_destinations(const vector<Node>& nodes, int idx) {\n    vector<uint8_t> rev;\n    while (idx != -1 && nodes[idx].parent != -1) {\n        rev.push_back(nodes[idx].actionTo);\n        idx = nodes[idx].parent;\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nstruct ReplayResult {\n    State st;\n    int energy = 0;\n    vector<pair<int,int>> ops;\n};\n\nReplayResult replay_destinations(const State& rawInit, const vector<uint8_t>& dests) {\n    ReplayResult rr;\n    rr.st = rawInit;\n    rr.energy = 0;\n    rr.ops.clear();\n\n    pop_all(rr.st, &rr.ops);\n\n    for (uint8_t to : dests) {\n        if (rr.st.cur > N) break;\n\n        int cur = rr.st.cur;\n        int s = rr.st.st_of[cur];\n        int p = rr.st.pos[cur];\n\n        if (p + 1 >= (int)rr.st.h[s]) {\n            pop_all(rr.st, &rr.ops);\n            continue;\n        }\n\n        int v = rr.st.a[s][p + 1];\n        int len = (int)rr.st.h[s] - p - 1;\n\n        rr.ops.push_back({v, (int)to});\n        rr.energy += len + 1;\n        move_blockers(rr.st, (int)to - 1);\n        pop_all(rr.st, &rr.ops);\n    }\n    return rr;\n}\n\nbool validate_result(const State& rawInit, const Result& res) {\n    State st = rawInit;\n    int energy = 0;\n\n    for (auto [v, to] : res.ops) {\n        if (to == 0) {\n            if (st.cur != v) return false;\n            if (v < 1 || v > N) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            if ((int)st.pos[v] + 1 != (int)st.h[s]) return false;\n            --st.h[s];\n            st.st_of[v] = REMOVED;\n            ++st.cur;\n        } else {\n            if (v < 1 || v > N || to < 1 || to > M) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            int p = st.pos[v];\n            int dst = to - 1;\n            int len = (int)st.h[s] - p;\n            for (int i = p; i < (int)st.h[s]; ++i) {\n                uint16_t x = st.a[s][i];\n                st.a[dst][st.h[dst]] = x;\n                st.st_of[x] = (uint8_t)dst;\n                st.pos[x] = st.h[dst];\n                ++st.h[dst];\n            }\n            st.h[s] = (uint8_t)p;\n            energy += len + 1;\n        }\n    }\n    return st.cur == N + 1 && energy == res.energy && (int)res.ops.size() <= 5000;\n}\n\nResult run_beam(const State& rawInit, const Config& cfg, double deadline) {\n    State start = rawInit;\n    pop_all(start, nullptr);\n\n    vector<Node> nodes;\n    nodes.reserve(cfg.width * 260 + 10);\n    nodes.push_back(Node{start, 0, -1, 0});\n\n    if (start.cur > N) {\n        ReplayResult rr = replay_destinations(rawInit, {});\n        return Result{rr.energy, rr.ops};\n    }\n\n    vector<int> beam = {0};\n    int bestFinishedIdx = -1;\n    int bestFinishedCost = INF;\n\n    while (!beam.empty()) {\n        if (elapsed_sec() > deadline) break;\n\n        vector<TempChild> cand;\n        cand.reserve(beam.size() * (M - 1));\n\n        bool hasBestTemp = false;\n        TempChild bestTemp{};\n\n        for (int idx : beam) {\n            const Node& nd = nodes[idx];\n            const State& st = nd.st;\n\n            if (st.cur > N) {\n                if (nd.g < bestFinishedCost) {\n                    bestFinishedCost = nd.g;\n                    bestFinishedIdx = idx;\n                }\n                continue;\n            }\n\n            int cur = st.cur;\n            int s = st.st_of[cur];\n            int p = st.pos[cur];\n\n            if (p + 1 >= (int)st.h[s]) continue;\n\n            int len = (int)st.h[s] - p - 1;\n\n            for (int dst = 0; dst < M; ++dst) {\n                if (dst == s) continue;\n\n                TempChild tc;\n                tc.st = st;\n                move_blockers(tc.st, dst);\n                pop_all(tc.st, nullptr);\n                tc.g = nd.g + len + 1;\n                tc.hval = estimate(tc.st, cfg.mode);\n                tc.eval = tc.g + tc.hval;\n                tc.parent = idx;\n                tc.actionTo = (uint8_t)(dst + 1);\n                tc.cur = tc.st.cur;\n\n                if (tc.st.cur > N) {\n                    if (tc.g < bestFinishedCost &&\n                        (!hasBestTemp || tc.g < bestTemp.g)) {\n                        hasBestTemp = true;\n                        bestTemp = tc;\n                    }\n                } else {\n                    cand.push_back(std::move(tc));\n                }\n            }\n        }\n\n        if (hasBestTemp) {\n            nodes.push_back(Node{bestTemp.st, bestTemp.g, bestTemp.parent, bestTemp.actionTo});\n            bestFinishedIdx = (int)nodes.size() - 1;\n            bestFinishedCost = bestTemp.g;\n        }\n\n        if (cand.empty()) break;\n\n        vector<int> ord(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n        auto cmp = [&](int i, int j) {\n            const auto& A = cand[i];\n            const auto& B = cand[j];\n            if (A.eval != B.eval) return A.eval < B.eval;\n            if (A.hval != B.hval) return A.hval < B.hval;\n            if (A.cur != B.cur) return A.cur > B.cur;\n            if (A.g != B.g) return A.g < B.g;\n            return A.actionTo < B.actionTo;\n        };\n\n        if ((int)ord.size() > cfg.width) {\n            nth_element(ord.begin(), ord.begin() + cfg.width, ord.end(), cmp);\n            ord.resize(cfg.width);\n        }\n        sort(ord.begin(), ord.end(), cmp);\n\n        vector<int> nextBeam;\n        nextBeam.reserve(ord.size());\n        for (int id : ord) {\n            const auto& tc = cand[id];\n            nodes.push_back(Node{tc.st, tc.g, tc.parent, tc.actionTo});\n            nextBeam.push_back((int)nodes.size() - 1);\n        }\n        beam.swap(nextBeam);\n    }\n\n    Result best;\n    best.energy = INF;\n\n    if (bestFinishedIdx != -1) {\n        auto dests = collect_destinations(nodes, bestFinishedIdx);\n        ReplayResult rr = replay_destinations(rawInit, dests);\n        if (rr.st.cur == N + 1) {\n            best.energy = rr.energy;\n            best.ops = std::move(rr.ops);\n        }\n    }\n\n    // If interrupted or beam-pruned too hard, complete a few good beam states greedily.\n    for (int t = 0; t < (int)beam.size() && t < 3 && elapsed_sec() <= deadline + 0.03; ++t) {\n        int idx = beam[t];\n        auto dests = collect_destinations(nodes, idx);\n        ReplayResult pref = replay_destinations(rawInit, dests);\n        Result tail = greedy_complete(pref.st, cfg.mode, cfg.greedyDepth);\n\n        Result candRes;\n        candRes.energy = pref.energy + tail.energy;\n        candRes.ops = std::move(pref.ops);\n        candRes.ops.insert(candRes.ops.end(), tail.ops.begin(), tail.ops.end());\n\n        if (candRes.energy < best.energy ||\n            (candRes.energy == best.energy && candRes.ops.size() < best.ops.size())) {\n            best = std::move(candRes);\n        }\n    }\n\n    // Absolute fallback.\n    if (best.energy == INF) {\n        ReplayResult pref = replay_destinations(rawInit, {});\n        Result tail = greedy_complete(pref.st, cfg.mode, max(1, cfg.greedyDepth));\n        best.energy = pref.energy + tail.energy;\n        best.ops = std::move(pref.ops);\n        best.ops.insert(best.ops.end(), tail.ops.begin(), tail.ops.end());\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n\n    State rawInit{};\n    rawInit.cur = 1;\n    for (int i = 0; i < M; ++i) {\n        rawInit.h[i] = N / M;\n        for (int j = 0; j < N / M; ++j) {\n            int x;\n            cin >> x;\n            rawInit.a[i][j] = (uint16_t)x;\n            rawInit.st_of[x] = (uint8_t)i;\n            rawInit.pos[x] = (uint8_t)j;\n        }\n    }\n\n    vector<Config> configs = {\n        {200, 0, 2},\n        {140, 1, 2},\n        {100, 3, 1},\n        {1,   0, 2},\n        {1,   1, 2},\n    };\n\n    Result best;\n    best.energy = INF;\n\n    double deadline = 1.90;\n\n    for (const auto& cfg : configs) {\n        if (elapsed_sec() > deadline) break;\n        Result cur = run_beam(rawInit, cfg, deadline);\n        if (validate_result(rawInit, cur)) {\n            if (cur.energy < best.energy ||\n                (cur.energy == best.energy && cur.ops.size() < best.ops.size())) {\n                best = std::move(cur);\n            }\n        }\n    }\n\n    // Safety fallback if something unexpected happened.\n    if (best.energy == INF) {\n        ReplayResult pref = replay_destinations(rawInit, {});\n        Result tail = greedy_complete(pref.st, 0, 2);\n        best.energy = pref.energy + tail.energy;\n        best.ops = std::move(pref.ops);\n        best.ops.insert(best.ops.end(), tail.ops.begin(), tail.ops.end());\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXV = 1600;\nstatic constexpr long long INF_NUM = (1LL << 62);\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = chrono::steady_clock::now().time_since_epoch().count()) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next() % (uint64_t)n); }\n};\n\nstruct Score {\n    long long num;\n    int L;\n};\n\nstatic inline bool better_score(const Score& a, const Score& b) {\n    __int128 lhs = (__int128)a.num * b.L;\n    __int128 rhs = (__int128)b.num * a.L;\n    if (lhs != rhs) return lhs < rhs;\n    return a.L < b.L;\n}\n\nstruct TreeCand {\n    vector<int> parent;\n    Score score;\n};\n\nint N, Vn;\nvector<int> graph_[MAXV];\nvector<int> children_[MAXV];\nint dirt_[MAXV];\nlong long imp_raw_[MAXV];\nlong long imp_smooth_[MAXV];\n\nint sz_[MAXV];\nlong long subImp_[MAXV];\nlong long subD_[MAXV];\n\nint firstOcc_[MAXV];\nint lastOcc_[MAXV];\nlong long gapAcc_[MAXV];\n\nvector<int> posbuf;\nXorShift64 rng;\n\ninline int vid(int r, int c) { return r * N + c; }\n\ninline char move_char(int a, int b) {\n    if (b == a + 1) return 'R';\n    if (b == a - 1) return 'L';\n    if (b == a + N) return 'D';\n    return 'U';\n}\n\ninline long long noise_rand(long long noise) {\n    if (noise == 0) return 0;\n    return (long long)(rng.next() % (uint64_t)(2 * noise + 1)) - noise;\n}\n\nScore evaluate_parent(const vector<int>& parent, const long long* orderImp, string* routeOut = nullptr) {\n    for (int i = 0; i < Vn; i++) children_[i].clear();\n    for (int v = 1; v < Vn; v++) children_[parent[v]].push_back(v);\n\n    auto dfs1 = [&](auto&& self, int u) -> void {\n        sz_[u] = 1;\n        subImp_[u] = orderImp[u];\n        subD_[u] = dirt_[u];\n        for (int c : children_[u]) self(self, c);\n\n        sort(children_[u].begin(), children_[u].end(), [&](int a, int b) {\n            __int128 lhs = (__int128)subImp_[a] * sz_[b];\n            __int128 rhs = (__int128)subImp_[b] * sz_[a];\n            if (lhs != rhs) return lhs > rhs;   // higher density first\n            if (subD_[a] != subD_[b]) return subD_[a] > subD_[b];\n            return a < b;\n        });\n\n        for (int c : children_[u]) {\n            sz_[u] += sz_[c];\n            subImp_[u] += subImp_[c];\n            subD_[u] += subD_[c];\n        }\n    };\n    dfs1(dfs1, 0);\n\n    posbuf.clear();\n    posbuf.reserve(2 * Vn);\n    posbuf.push_back(0);\n\n    string route;\n    if (routeOut) route.reserve(2 * (Vn - 1));\n\n    auto dfs2 = [&](auto&& self, int u) -> void {\n        for (int c : children_[u]) {\n            posbuf.push_back(c);\n            if (routeOut) route.push_back(move_char(u, c));\n            self(self, c);\n            posbuf.push_back(u);\n            if (routeOut) route.push_back(move_char(c, u));\n        }\n    };\n    dfs2(dfs2, 0);\n\n    int L = (int)posbuf.size() - 1;\n    fill(firstOcc_, firstOcc_ + Vn, -1);\n    fill(gapAcc_, gapAcc_ + Vn, 0LL);\n\n    long long num = 0;\n    for (int t = 1; t <= L; t++) {\n        int x = posbuf[t];\n        if (firstOcc_[x] == -1) {\n            firstOcc_[x] = t;\n        } else {\n            long long g = t - lastOcc_[x];\n            gapAcc_[x] += g * (g - 1) / 2;\n        }\n        lastOcc_[x] = t;\n    }\n    for (int x = 0; x < Vn; x++) {\n        if (firstOcc_[x] == -1) return {INF_NUM, L};\n        long long g = firstOcc_[x] + L - lastOcc_[x];\n        gapAcc_[x] += g * (g - 1) / 2;\n        num += gapAcc_[x] * 1LL * dirt_[x];\n    }\n\n    if (routeOut) *routeOut = std::move(route);\n    return {num, L};\n}\n\nvoid refresh_topology(const vector<int>& parent, vector<int>& tin, vector<int>& tout, vector<int>& depth) {\n    for (int i = 0; i < Vn; i++) children_[i].clear();\n    for (int v = 1; v < Vn; v++) children_[parent[v]].push_back(v);\n\n    int timer = 0;\n    auto dfs = [&](auto&& self, int u, int dep) -> void {\n        tin[u] = timer++;\n        depth[u] = dep;\n        for (int c : children_[u]) self(self, c, dep + 1);\n        tout[u] = timer;\n    };\n    dfs(dfs, 0, 0);\n}\n\nvector<int> gen_weighted_dfs(const long long* imp, long long noise) {\n    vector<int> parent(Vn, -1);\n    vector<char> vis(Vn, 0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        vis[u] = 1;\n        array<pair<long long, int>, 4> cand;\n        int m = 0;\n        for (int to : graph_[u]) cand[m++] = {imp[to] + noise_rand(noise), to};\n        sort(cand.begin(), cand.begin() + m, [](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        for (int i = 0; i < m; i++) {\n            int to = cand[i].second;\n            if (!vis[to]) {\n                parent[to] = u;\n                self(self, to);\n            }\n        }\n    };\n    dfs(dfs, 0);\n    return parent;\n}\n\nvector<int> gen_prim(const long long* imp, long long noise, int depthPenalty) {\n    struct Node {\n        long long key;\n        uint64_t tie;\n        int from, to;\n        bool operator<(const Node& other) const {\n            if (key != other.key) return key < other.key;\n            return tie < other.tie;\n        }\n    };\n\n    vector<int> parent(Vn, -1), depth(Vn, 0);\n    vector<char> used(Vn, 0);\n    priority_queue<Node> pq;\n\n    used[0] = 1;\n    int cnt = 1;\n\n    auto push_edges = [&](int u) {\n        for (int to : graph_[u]) {\n            if (!used[to]) {\n                long long key = imp[to] - 1LL * depthPenalty * depth[u] + noise_rand(noise);\n                pq.push({key, rng.next(), u, to});\n            }\n        }\n    };\n    push_edges(0);\n\n    while (cnt < Vn && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n        if (used[cur.to]) continue;\n        used[cur.to] = 1;\n        parent[cur.to] = cur.from;\n        depth[cur.to] = depth[cur.from] + 1;\n        cnt++;\n        push_edges(cur.to);\n    }\n\n    if (cnt < Vn) return gen_weighted_dfs(imp, 0);\n    return parent;\n}\n\nvoid consider_pool(vector<TreeCand>& pool, const vector<int>& parent, const Score& score, int maxPool = 4) {\n    if ((int)pool.size() >= maxPool && !better_score(score, pool.back().score)) return;\n    pool.push_back({parent, score});\n    sort(pool.begin(), pool.end(), [](const TreeCand& a, const TreeCand& b) {\n        return better_score(a.score, b.score);\n    });\n    if ((int)pool.size() > maxPool) pool.pop_back();\n}\n\nvector<int> random_tree() {\n    bool useDFS = (rng.next() & 1);\n    const long long* imp = ((rng.next() & 1) ? imp_raw_ : imp_smooth_);\n    if (useDFS) {\n        static const long long noises[] = {0, 5000, 10000, 20000, 40000, 80000};\n        long long noise = noises[rng.next_int((int)(sizeof(noises) / sizeof(noises[0])))];\n        return gen_weighted_dfs(imp, noise);\n    } else {\n        static const long long noises[] = {0, 10000, 30000, 60000};\n        static const int pens[] = {0, 100, 300, 600};\n        long long noise = noises[rng.next_int((int)(sizeof(noises) / sizeof(noises[0])))];\n        int pen = pens[rng.next_int((int)(sizeof(pens) / sizeof(pens[0])))];\n        return gen_prim(imp, noise, pen);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<string> h(N - 1), vwall(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vwall[i];\n\n    Vn = N * N;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> dirt_[vid(i, j)];\n        }\n    }\n\n    for (int i = 0; i < Vn; i++) graph_[i].clear();\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int a = vid(i, j);\n            if (i + 1 < N && h[i][j] == '0') {\n                int b = vid(i + 1, j);\n                graph_[a].push_back(b);\n                graph_[b].push_back(a);\n            }\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int b = vid(i, j + 1);\n                graph_[a].push_back(b);\n                graph_[b].push_back(a);\n            }\n        }\n    }\n\n    for (int u = 0; u < Vn; u++) {\n        long long s = 0;\n        for (int to : graph_[u]) s += dirt_[to];\n        imp_raw_[u] = 100LL * dirt_[u];\n        imp_smooth_[u] = 100LL * dirt_[u] + 35LL * s;\n    }\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    const double TL = 1.92;\n\n    vector<TreeCand> pool;\n\n    // Initial candidates\n    {\n        const long long* imps[2] = {imp_raw_, imp_smooth_};\n\n        for (int t = 0; t < 2; t++) {\n            const long long* imp = imps[t];\n            vector<long long> dfsNoises = {0, 5000, 20000, 60000};\n            for (long long noise : dfsNoises) {\n                int reps = (noise == 0 ? 1 : 2);\n                for (int rep = 0; rep < reps; rep++) {\n                    auto p = gen_weighted_dfs(imp, noise);\n                    auto s = evaluate_parent(p, imp_smooth_);\n                    consider_pool(pool, p, s);\n                }\n            }\n\n            vector<long long> primNoises = {0, 10000, 40000};\n            vector<int> pens = {0, 150, 400};\n            for (long long noise : primNoises) {\n                for (int pen : pens) {\n                    auto p = gen_prim(imp, noise, pen);\n                    auto s = evaluate_parent(p, imp_smooth_);\n                    consider_pool(pool, p, s);\n                }\n            }\n        }\n    }\n\n    if (pool.empty()) {\n        auto p = gen_weighted_dfs(imp_smooth_, 0);\n        auto s = evaluate_parent(p, imp_smooth_);\n        consider_pool(pool, p, s);\n    }\n\n    TreeCand best = pool[0];\n    vector<int> currentParent = best.parent;\n    Score currentScore = best.score;\n\n    vector<int> tin(Vn), tout(Vn), depth(Vn);\n    refresh_topology(currentParent, tin, tout, depth);\n\n    int stall = 0;\n    int iter = 0;\n\n    while (true) {\n        if ((iter++ & 63) == 0 && elapsed() > TL) break;\n\n        if (stall >= 250) {\n            if (!pool.empty() && rng.next_int(100) < 70) {\n                int lim = min(3, (int)pool.size());\n                int idx = rng.next_int(lim);\n                currentParent = pool[idx].parent;\n                currentScore = pool[idx].score;\n            } else {\n                auto p = random_tree();\n                auto s = evaluate_parent(p, imp_smooth_);\n                consider_pool(pool, p, s);\n                currentParent = std::move(p);\n                currentScore = s;\n                if (better_score(currentScore, best.score)) {\n                    best = {currentParent, currentScore};\n                }\n            }\n            refresh_topology(currentParent, tin, tout, depth);\n            stall = 0;\n            continue;\n        }\n\n        int u = -1, w = -1;\n        bool ok = false;\n\n        for (int tries = 0; tries < 20 && !ok; tries++) {\n            u = 1 + rng.next_int(Vn - 1);\n\n            int opts[4];\n            int m = 0;\n            for (int to : graph_[u]) {\n                if (to == currentParent[u]) continue;\n                if (tin[u] <= tin[to] && tout[to] <= tout[u]) continue; // descendant => cycle\n                opts[m++] = to;\n            }\n            if (m == 0) continue;\n\n            if (m == 1 || rng.next_int(100) < 30) {\n                w = opts[rng.next_int(m)];\n            } else {\n                long long bestKey = LLONG_MIN;\n                int bestTo = opts[0];\n                for (int i = 0; i < m; i++) {\n                    int to = opts[i];\n                    long long key = imp_smooth_[to] - 250LL * depth[to] + (long long)(rng.next() % 10000);\n                    if (key > bestKey) {\n                        bestKey = key;\n                        bestTo = to;\n                    }\n                }\n                w = bestTo;\n            }\n            ok = true;\n        }\n\n        if (!ok) {\n            stall++;\n            continue;\n        }\n\n        vector<int> candParent = currentParent;\n        candParent[u] = w;\n        Score candScore = evaluate_parent(candParent, imp_smooth_);\n\n        if (better_score(candScore, currentScore)) {\n            currentParent.swap(candParent);\n            currentScore = candScore;\n            refresh_topology(currentParent, tin, tout, depth);\n            stall = 0;\n\n            consider_pool(pool, currentParent, currentScore);\n            if (better_score(currentScore, best.score)) {\n                best = {currentParent, currentScore};\n            }\n        } else {\n            stall++;\n        }\n    }\n\n    // Final route: compare two child-order metrics and output the better one.\n    string routeA, routeB;\n    Score sA = evaluate_parent(best.parent, imp_smooth_, &routeA);\n    Score sB = evaluate_parent(best.parent, imp_raw_, &routeB);\n\n    if (better_score(sB, sA)) {\n        cout << routeB << '\\n';\n    } else {\n        cout << routeA << '\\n';\n    }\n\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"Ofast,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool same(int a, int b) { return find(a) == find(b); }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int NMAX = 15;\n    static constexpr int PMAX = 225;\n    static constexpr int MMAX = 200;\n    static constexpr int INF = 1e9;\n\n    int N, M;\n    int si, sj, startPos;\n\n    vector<string> board;\n    vector<string> words;\n    vector<array<int, 5>> w;\n\n    array<vector<int>, 26> occ;\n    int man[PMAX][PMAX];\n\n    int ov[MMAX][MMAX];\n    int lastc[MMAX];\n    int endCnt[MMAX];\n\n    struct MatInfo {\n        vector<uint16_t> a; // row-major\n    };\n    vector<MatInfo> mats; // [26][M][5]\n\n    vector<vector<uint16_t>> startVec; // per word, costs to each end occurrence\n    int startMin[MMAX];\n    int startApprox[MMAX];\n\n    int edgeMin[MMAX][MMAX];\n    int edgeApprox[MMAX][MMAX];\n\n    uint32_t baseSeed = 1;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 1.88;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n    inline bool timeup(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline MatInfo& MAT(int c, int j, int st) {\n        return mats[(c * M + j) * 5 + st];\n    }\n    inline const MatInfo& MAT(int c, int j, int st) const {\n        return mats[(c * M + j) * 5 + st];\n    }\n\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        cin >> si >> sj;\n        startPos = si * N + sj;\n\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n\n        words.resize(M);\n        w.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) w[i][k] = words[i][k] - 'A';\n            lastc[i] = w[i][4];\n        }\n    }\n\n    void buildSeed() {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (auto& row : board) for (char c : row) mix((uint64_t)c);\n        for (auto& s : words) for (char c : s) mix((uint64_t)c);\n        baseSeed = (uint32_t)(h ^ (h >> 32));\n        if (baseSeed == 0) baseSeed = 1;\n    }\n\n    void precomputeKeyboard() {\n        for (auto& v : occ) v.clear();\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                occ[board[i][j] - 'A'].push_back(id);\n            }\n        }\n        for (int p = 0; p < N * N; p++) {\n            int pi = p / N, pj = p % N;\n            for (int q = 0; q < N * N; q++) {\n                int qi = q / N, qj = q % N;\n                man[p][q] = abs(pi - qi) + abs(pj - qj);\n            }\n        }\n        for (int i = 0; i < M; i++) endCnt[i] = (int)occ[lastc[i]].size();\n    }\n\n    int calcOverlap(const string& a, const string& b) const {\n        for (int len = 4; len >= 1; len--) {\n            bool ok = true;\n            for (int k = 0; k < len; k++) {\n                if (a[5 - len + k] != b[k]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return len;\n        }\n        return 0;\n    }\n\n    void precomputeOverlaps() {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                ov[i][j] = (i == j ? 0 : calcOverlap(words[i], words[j]));\n            }\n        }\n    }\n\n    vector<uint16_t> buildMatFromSources(const vector<int>& srcPos, int wid, int st) {\n        int R = (int)srcPos.size();\n        int C = endCnt[wid];\n        vector<uint16_t> res(R * C);\n\n        int prevCost[PMAX], curCost[PMAX];\n\n        for (int r = 0; r < R; r++) {\n            int src = srcPos[r];\n\n            int prevChar = w[wid][st];\n            int pcnt = (int)occ[prevChar].size();\n            const vector<int>& firstPos = occ[prevChar];\n            for (int i = 0; i < pcnt; i++) {\n                prevCost[i] = man[src][firstPos[i]] + 1;\n            }\n\n            for (int k = st + 1; k < 5; k++) {\n                int curChar = w[wid][k];\n                const vector<int>& prevPos = occ[prevChar];\n                const vector<int>& curPos = occ[curChar];\n                int ccnt = (int)curPos.size();\n\n                for (int ci = 0; ci < ccnt; ci++) {\n                    int q = curPos[ci];\n                    int best = INF;\n                    for (int pi = 0; pi < pcnt; pi++) {\n                        int cand = prevCost[pi] + man[prevPos[pi]][q] + 1;\n                        if (cand < best) best = cand;\n                    }\n                    curCost[ci] = best;\n                }\n                for (int i = 0; i < ccnt; i++) prevCost[i] = curCost[i];\n                pcnt = ccnt;\n                prevChar = curChar;\n            }\n\n            for (int e = 0; e < C; e++) {\n                res[r * C + e] = (uint16_t)prevCost[e];\n            }\n        }\n        return res;\n    }\n\n    void precomputeMatrices() {\n        mats.resize(26 * M * 5);\n        startVec.assign(M, {});\n\n        for (int j = 0; j < M; j++) {\n            vector<int> src = {startPos};\n            auto v = buildMatFromSources(src, j, 0);\n            startVec[j].assign(v.begin(), v.end());\n\n            int mn = INF, sum = 0;\n            for (uint16_t x : startVec[j]) {\n                mn = min(mn, (int)x);\n                sum += x;\n            }\n            startMin[j] = mn;\n            int avg = sum / max(1, (int)startVec[j].size());\n            startApprox[j] = (mn + avg) / 2;\n        }\n\n        for (int c = 0; c < 26; c++) {\n            for (int j = 0; j < M; j++) {\n                for (int st = 0; st < 5; st++) {\n                    MAT(c, j, st).a = buildMatFromSources(occ[c], j, st);\n                }\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            edgeMin[i][i] = INF / 4;\n            edgeApprox[i][i] = INF / 4;\n            for (int j = 0; j < M; j++) if (i != j) {\n                int c = lastc[i];\n                int st = ov[i][j];\n                const auto& arr = MAT(c, j, st).a;\n                int rows = (int)occ[c].size();\n                int cols = endCnt[j];\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                const uint16_t* p = arr.data();\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    const uint16_t* row = p + r * cols;\n                    for (int e = 0; e < cols; e++) {\n                        int v = row[e];\n                        if (v < rowMin) rowMin = v;\n                        if (v < globalMin) globalMin = v;\n                    }\n                    sumRowMin += rowMin;\n                }\n                int avgRowMin = (int)(sumRowMin / max(1, rows));\n                edgeMin[i][j] = globalMin;\n                edgeApprox[i][j] = (globalMin + avgRowMin) / 2;\n            }\n        }\n    }\n\n    int evalPerm(const vector<int>& perm) const {\n        int dp[PMAX], ndp[PMAX];\n        int first = perm[0];\n        int cnt = endCnt[first];\n        for (int e = 0; e < cnt; e++) dp[e] = startVec[first][e];\n\n        for (int idx = 1; idx < (int)perm.size(); idx++) {\n            int a = perm[idx - 1];\n            int b = perm[idx];\n            int c = lastc[a];\n            int st = ov[a][b];\n            const auto& arr = MAT(c, b, st).a;\n            int rows = (int)occ[c].size();\n            int cols = endCnt[b];\n\n            for (int e = 0; e < cols; e++) ndp[e] = INF;\n            const uint16_t* matp = arr.data();\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const uint16_t* row = matp + r * cols;\n                for (int e = 0; e < cols; e++) {\n                    int cand = base + row[e];\n                    if (cand < ndp[e]) ndp[e] = cand;\n                }\n            }\n\n            cnt = cols;\n            for (int e = 0; e < cnt; e++) dp[e] = ndp[e];\n        }\n\n        int ans = INF;\n        for (int e = 0; e < cnt; e++) ans = min(ans, dp[e]);\n        return ans;\n    }\n\n    int transitionCostAndDP(const int* dp, int curWord, int nextWord, int* outDP) const {\n        int c = lastc[curWord];\n        int st = ov[curWord][nextWord];\n        const auto& arr = MAT(c, nextWord, st).a;\n        int rows = (int)occ[c].size();\n        int cols = endCnt[nextWord];\n\n        for (int e = 0; e < cols; e++) outDP[e] = INF;\n        const uint16_t* matp = arr.data();\n\n        for (int r = 0; r < rows; r++) {\n            int base = dp[r];\n            const uint16_t* row = matp + r * cols;\n            for (int e = 0; e < cols; e++) {\n                int cand = base + row[e];\n                if (cand < outDP[e]) outDP[e] = cand;\n            }\n        }\n\n        int best = INF;\n        for (int e = 0; e < cols; e++) best = min(best, outDP[e]);\n        return best;\n    }\n\n    vector<int> buildStringWordOrder(const vector<int>& perm) const {\n        return perm;\n    }\n\n    string buildString(const vector<int>& perm) const {\n        string s;\n        if (perm.empty()) return s;\n        s.reserve(5 * (int)perm.size());\n        s += words[perm[0]];\n        for (int i = 1; i < (int)perm.size(); i++) {\n            int o = ov[perm[i - 1]][perm[i]];\n            s.append(words[perm[i]].begin() + o, words[perm[i]].end());\n        }\n        return s;\n    }\n\n    vector<int> initGreedyAppend(int firstWord, uint32_t seed, bool randomized, int topNext = 4) const {\n        mt19937 rng(seed);\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> used(M, 0);\n\n        int curDP[PMAX], tmpDP[PMAX], chosenDP[PMAX];\n\n        perm.push_back(firstWord);\n        used[firstWord] = 1;\n        int curCnt = endCnt[firstWord];\n        for (int e = 0; e < curCnt; e++) curDP[e] = startVec[firstWord][e];\n        int curWord = firstWord;\n\n        while ((int)perm.size() < M) {\n            vector<pair<int, int>> cand; // (score, word)\n            cand.reserve(M - perm.size());\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                int score = transitionCostAndDP(curDP, curWord, j, tmpDP);\n                cand.push_back({score, j});\n            }\n            sort(cand.begin(), cand.end());\n\n            int pickIdx = 0;\n            if (randomized) {\n                int lim = min<int>(topNext, cand.size());\n                pickIdx = uniform_int_distribution<int>(0, lim - 1)(rng);\n            }\n            int nxt = cand[pickIdx].second;\n\n            transitionCostAndDP(curDP, curWord, nxt, chosenDP);\n            curCnt = endCnt[nxt];\n            for (int e = 0; e < curCnt; e++) curDP[e] = chosenDP[e];\n\n            perm.push_back(nxt);\n            used[nxt] = 1;\n            curWord = nxt;\n        }\n        return perm;\n    }\n\n    vector<int> initCheapestInsertion(uint32_t seed, bool randomized) const {\n        mt19937 rng(seed);\n\n        if (M == 1) return {0};\n\n        struct PairCand {\n            int cost, a, b;\n        };\n        vector<PairCand> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) if (i != j) {\n                pairs.push_back({startApprox[i] + edgeApprox[i][j], i, j});\n            }\n        }\n        sort(pairs.begin(), pairs.end(), [](const PairCand& x, const PairCand& y) {\n            if (x.cost != y.cost) return x.cost < y.cost;\n            if (x.a != y.a) return x.a < y.a;\n            return x.b < y.b;\n        });\n\n        int pick = 0;\n        if (randomized) {\n            int lim = min<int>(10, pairs.size());\n            pick = uniform_int_distribution<int>(0, lim - 1)(rng);\n        }\n\n        vector<int> perm = {pairs[pick].a, pairs[pick].b};\n        vector<char> used(M, 0);\n        used[pairs[pick].a] = used[pairs[pick].b] = 1;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                int inc, x, pos;\n            };\n            vector<Cand> bests;\n            int keep = randomized ? 6 : 1;\n\n            auto push_cand = [&](Cand c) {\n                bests.push_back(c);\n                sort(bests.begin(), bests.end(), [](const Cand& a, const Cand& b) {\n                    if (a.inc != b.inc) return a.inc < b.inc;\n                    if (a.x != b.x) return a.x < b.x;\n                    return a.pos < b.pos;\n                });\n                if ((int)bests.size() > keep) bests.pop_back();\n            };\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                // front\n                push_cand({startApprox[x] + edgeApprox[x][perm[0]] - startApprox[perm[0]], x, 0});\n                // middle\n                for (int i = 1; i < (int)perm.size(); i++) {\n                    int inc = edgeApprox[perm[i - 1]][x] + edgeApprox[x][perm[i]] - edgeApprox[perm[i - 1]][perm[i]];\n                    push_cand({inc, x, i});\n                }\n                // back\n                push_cand({edgeApprox[perm.back()][x], x, (int)perm.size()});\n            }\n\n            int idx = 0;\n            if (randomized) idx = uniform_int_distribution<int>(0, (int)bests.size() - 1)(rng);\n            auto c = bests[idx];\n            perm.insert(perm.begin() + c.pos, c.x);\n            used[c.x] = 1;\n        }\n\n        return perm;\n    }\n\n    vector<int> initEdgeGreedy(uint32_t seed, bool randomized) const {\n        struct E {\n            int u, v, cost, ov;\n        };\n        vector<E> edges;\n        edges.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) if (i != j) {\n                edges.push_back({i, j, edgeApprox[i][j], ov[i][j]});\n            }\n        }\n\n        mt19937 rng(seed);\n        if (randomized) shuffle(edges.begin(), edges.end(), rng);\n\n        stable_sort(edges.begin(), edges.end(), [&](const E& a, const E& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.ov != b.ov) return a.ov > b.ov;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        vector<int> in(M, -1), out(M, -1);\n        DSU dsu(M);\n        int used = 0;\n        for (auto& e : edges) {\n            if (out[e.u] != -1) continue;\n            if (in[e.v] != -1) continue;\n            if (dsu.same(e.u, e.v)) continue;\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n            used++;\n            if (used == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) if (in[i] == -1) {\n            head = i;\n            break;\n        }\n\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> seen(M, 0);\n        int cur = head;\n        while (cur != -1 && !seen[cur]) {\n            perm.push_back(cur);\n            seen[cur] = 1;\n            cur = out[cur];\n        }\n        for (int i = 0; i < M; i++) if (!seen[i]) perm.push_back(i);\n        return perm;\n    }\n\n    inline long long linkApprox(int prev, int cur) const {\n        if (cur == -1) return 0;\n        if (prev == -1) return startApprox[cur];\n        return edgeApprox[prev][cur];\n    }\n\n    long long relocateDelta(const vector<int>& p, int a, int b) const {\n        if (a == b) return 0;\n        int n = (int)p.size();\n        int x = p[a];\n        int A = (a > 0 ? p[a - 1] : -1);\n        int B = (a + 1 < n ? p[a + 1] : -1);\n\n        long long delta = 0;\n\n        // remove x\n        delta -= linkApprox(A, x);\n        delta -= linkApprox(x, B);\n        delta += linkApprox(A, B);\n\n        // insert x at position b after erase semantics:\n        int C, D;\n        if (b <= a - 1) {\n            C = (b > 0 ? p[b - 1] : -1);\n            D = p[b];\n        } else {\n            C = p[b];\n            D = (b + 1 < n ? p[b + 1] : -1);\n        }\n\n        delta -= linkApprox(C, D);\n        delta += linkApprox(C, x);\n        delta += linkApprox(x, D);\n\n        return delta;\n    }\n\n    long long swapDelta(const vector<int>& p, int a, int b) const {\n        if (a == b) return 0;\n        if (a > b) swap(a, b);\n        int n = (int)p.size();\n\n        int A = p[a], B = p[b];\n        int pA = (a > 0 ? p[a - 1] : -1);\n        int nA = (a + 1 < n ? p[a + 1] : -1);\n        int pB = (b > 0 ? p[b - 1] : -1);\n        int nB = (b + 1 < n ? p[b + 1] : -1);\n\n        long long oldCost = 0, newCost = 0;\n\n        if (a + 1 == b) {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, A);\n            newCost += linkApprox(A, nB);\n        } else {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, nA);\n            oldCost += linkApprox(pB, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, nA);\n            newCost += linkApprox(pB, A);\n            newCost += linkApprox(A, nB);\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyRelocate(vector<int>& p, int a, int b) const {\n        int x = p[a];\n        p.erase(p.begin() + a);\n        p.insert(p.begin() + b, x);\n    }\n\n    void applyMove(vector<int>& p, int type, int a, int b) const {\n        if (type == 0) applyRelocate(p, a, b);\n        else swap(p[a], p[b]);\n    }\n\n    struct MoveCand {\n        long long d;\n        int type, a, b;\n    };\n\n    pair<vector<int>, int> localSearch(vector<int> perm, int curExact, int maxIter, int topK) {\n        int n = (int)perm.size();\n\n        for (int iter = 0; iter < maxIter && !timeup(0.06); iter++) {\n            vector<MoveCand> cand;\n            cand.reserve(n * (n - 1) + n * (n - 1) / 2);\n\n            for (int a = 0; a < n; a++) {\n                for (int b = 0; b < n; b++) {\n                    if (a == b) continue;\n                    long long d = relocateDelta(perm, a, b);\n                    cand.push_back({d, 0, a, b});\n                }\n            }\n            for (int a = 0; a < n; a++) {\n                for (int b = a + 1; b < n; b++) {\n                    long long d = swapDelta(perm, a, b);\n                    cand.push_back({d, 1, a, b});\n                }\n            }\n\n            auto comp = [](const MoveCand& x, const MoveCand& y) {\n                if (x.d != y.d) return x.d < y.d;\n                if (x.type != y.type) return x.type < y.type;\n                if (x.a != y.a) return x.a < y.a;\n                return x.b < y.b;\n            };\n\n            int K = min<int>(topK, cand.size());\n            nth_element(cand.begin(), cand.begin() + K, cand.end(), comp);\n            cand.resize(K);\n            sort(cand.begin(), cand.end(), comp);\n\n            bool improved = false;\n            int bestExact = curExact;\n            vector<int> bestPerm;\n\n            int tested = 0;\n            for (auto& mv : cand) {\n                if (timeup(0.05)) break;\n                vector<int> np = perm;\n                applyMove(np, mv.type, mv.a, mv.b);\n                int ex = evalPerm(np);\n                tested++;\n                if (ex < bestExact) {\n                    bestExact = ex;\n                    bestPerm.swap(np);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            perm.swap(bestPerm);\n            curExact = bestExact;\n        }\n\n        return {perm, curExact};\n    }\n\n    void randomKick(vector<int>& perm, mt19937& rng, int cnt) const {\n        int n = (int)perm.size();\n        for (int t = 0; t < cnt; t++) {\n            if (uniform_int_distribution<int>(0, 1)(rng) == 0) {\n                int a = uniform_int_distribution<int>(0, n - 1)(rng);\n                int b = uniform_int_distribution<int>(0, n - 1)(rng);\n                if (a != b) swap(perm[a], perm[b]);\n            } else {\n                int a = uniform_int_distribution<int>(0, n - 1)(rng);\n                int b = uniform_int_distribution<int>(0, n - 1)(rng);\n                if (a != b) applyRelocate(perm, a, b);\n            }\n        }\n    }\n\n    pair<int, vector<int>> exactPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n\n        const auto& firstPos = occ[s[0] - 'A'];\n        vector<int> dpPrev(firstPos.size());\n        parent[0].assign(firstPos.size(), -1);\n        for (int i = 0; i < (int)firstPos.size(); i++) {\n            dpPrev[i] = man[startPos][firstPos[i]] + 1;\n        }\n\n        for (int t = 1; t < L; t++) {\n            const auto& prevPos = occ[s[t - 1] - 'A'];\n            const auto& curPos = occ[s[t] - 'A'];\n            vector<int> dpCur(curPos.size(), INF);\n            parent[t].assign(curPos.size(), -1);\n\n            for (int ci = 0; ci < (int)curPos.size(); ci++) {\n                int q = curPos[ci];\n                int best = INF, bestp = -1;\n                for (int pi = 0; pi < (int)prevPos.size(); pi++) {\n                    int cand = dpPrev[pi] + man[prevPos[pi]][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bestp = pi;\n                    }\n                }\n                dpCur[ci] = best;\n                parent[t][ci] = bestp;\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        int best = INF, idx = -1;\n        for (int i = 0; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < best) {\n                best = dpPrev[i];\n                idx = i;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = occ[s[L - 1] - 'A'][idx];\n        for (int t = L - 1; t >= 1; t--) {\n            idx = parent[t][idx];\n            path[t - 1] = occ[s[t - 1] - 'A'][idx];\n        }\n        return {best, path};\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        readInput();\n        buildSeed();\n        precomputeKeyboard();\n        precomputeOverlaps();\n        precomputeMatrices();\n\n        vector<int> startOrder(M);\n        iota(startOrder.begin(), startOrder.end(), 0);\n        sort(startOrder.begin(), startOrder.end(), [&](int a, int b) {\n            if (startApprox[a] != startApprox[b]) return startApprox[a] < startApprox[b];\n            return a < b;\n        });\n\n        struct SeedCand {\n            vector<int> perm;\n            int exact;\n        };\n        vector<SeedCand> seeds;\n\n        auto addSeed = [&](vector<int> p) {\n            int ex = evalPerm(p);\n            seeds.push_back({move(p), ex});\n        };\n\n        // Exact greedy append, deterministic from several starts\n        addSeed(initGreedyAppend(startOrder[0], baseSeed + 11, false));\n        addSeed(initGreedyAppend(startOrder[min(1, M - 1)], baseSeed + 12, false));\n        addSeed(initGreedyAppend(startOrder[min(2, M - 1)], baseSeed + 13, false));\n\n        // Exact greedy append, randomized\n        {\n            mt19937 rng(baseSeed + 100);\n            int lim = min(10, M);\n            for (int z = 0; z < 4 && !timeup(0.4); z++) {\n                int first = startOrder[uniform_int_distribution<int>(0, lim - 1)(rng)];\n                addSeed(initGreedyAppend(first, baseSeed + 21 + z, true));\n            }\n        }\n\n        // Static insertion / edge-greedy\n        if (!timeup(0.35)) addSeed(initCheapestInsertion(baseSeed + 31, false));\n        if (!timeup(0.35)) addSeed(initCheapestInsertion(baseSeed + 32, true));\n        if (!timeup(0.35)) addSeed(initEdgeGreedy(baseSeed + 41, false));\n        if (!timeup(0.35)) addSeed(initEdgeGreedy(baseSeed + 42, true));\n\n        sort(seeds.begin(), seeds.end(), [](const SeedCand& a, const SeedCand& b) {\n            return a.exact < b.exact;\n        });\n\n        vector<int> bestPerm = seeds[0].perm;\n        int bestExact = seeds[0].exact;\n\n        int topSeedCnt = min<int>(3, seeds.size());\n        for (int i = 0; i < topSeedCnt && !timeup(0.22); i++) {\n            int remainStyle = (elapsed() < 1.15 ? 2200 : 1400);\n            auto cur = localSearch(seeds[i].perm, seeds[i].exact, 8, remainStyle);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        // Iterated local search from the current best\n        mt19937 rng(baseSeed + 999);\n        int noImprove = 0;\n        while (!timeup(0.09)) {\n            vector<int> p = bestPerm;\n            randomKick(p, rng, 3);\n            int ex = evalPerm(p);\n\n            int K = (elapsed() < 1.45 ? 1200 : 700);\n            auto cur = localSearch(move(p), ex, 4, K);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n                noImprove = 0;\n            } else {\n                noImprove++;\n                if (noImprove >= 6 && elapsed() > 1.55) break;\n            }\n        }\n\n        string finalS = buildString(bestPerm);\n        auto [finalCost, path] = exactPathForString(finalS);\n\n        for (int pos : path) {\n            cout << (pos / N) << ' ' << (pos % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXQ = 64;\nstatic constexpr int WORDS = 7; // 7*64 = 448 >= 400\n\nusing ull = unsigned long long;\nusing Mask = array<ull, WORDS>;\n\nstruct Placement {\n    int di, dj;\n    Mask mask{};\n    array<unsigned char, MAXQ> contrib{};\n};\n\nstruct Field {\n    int sz = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> pls;\n};\n\nstruct State {\n    vector<int> choice;\n    array<short, MAXQ> setsum{};\n    vector<short> drillsum;\n    int pen = 0;     // exact drill squared-error\n    double div = 0;  // divination score\n};\n\nstruct UnionSummary {\n    bool hasPlausible = false;     // means best drill penalty == 0 and we summarized those\n    int bestPen = INT_MAX;\n    int distinctUnionCount = 0;\n\n    vector<Mask> masks;\n    vector<double> weights;\n\n    Mask bestMask{};\n    Mask must1{};\n    Mask maybe1{};\n\n    double bestWeight = 0.0;\n    double maxEntropy = -1.0;\n    int bestCell = -1;\n\n    vector<int> ambiguous;\n};\n\nstruct Solver {\n    int N, M, NN;\n    double eps, alpha;\n    int totalArea = 0;\n    int maxOps;\n    int ops = 0;\n    double compLog2 = 0.0;\n\n    vector<Field> fields;\n\n    int Qall;\n    vector<vector<int>> queryCells;\n    vector<int> qSize, qResp;\n    vector<char> qKnown;\n    vector<vector<double>> qScore; // qScore[q][predicted_sum]\n\n    vector<array<int,4>> cellQids; // row, col, mod2, mod3 qid\n\n    vector<int> drilledCells;\n    vector<int> drilledObs;\n    vector<int> cellObs; // -1 if unknown\n    vector<char> drilledFlag;\n\n    vector<State> pool;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point stTime;\n\n    Solver(): rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    // ---------- mask helpers ----------\n    static inline void mask_clear(Mask &m) { m.fill(0); }\n    static inline void mask_set(Mask &m, int idx) { m[idx >> 6] |= (1ULL << (idx & 63)); }\n    static inline bool mask_test(const Mask &m, int idx) { return (m[idx >> 6] >> (idx & 63)) & 1ULL; }\n    static inline void mask_or_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] |= b[i]; }\n    static inline void mask_and_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] &= b[i]; }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - stTime).count();\n    }\n\n    int activeQCount() const {\n        int c = 0;\n        for (char x : qKnown) c += x;\n        return c;\n    }\n\n    bool better(int p1, double d1, int p2, double d2) const {\n        if (p1 != p2) return p1 < p2;\n        return d1 + 1e-12 < d2;\n    }\n\n    int rand_int(int lim) {\n        return int(rng() % (uint64_t)lim);\n    }\n\n    // ---------- I/O ----------\n    void read_input() {\n        cin >> N >> M >> eps;\n        NN = N * N;\n        maxOps = 2 * NN;\n        alpha = 1.0 - 2.0 * eps;\n\n        fields.resize(M);\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            fields[k].sz = d;\n            fields[k].rel.resize(d);\n            int mxr = 0, mxc = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].rel[t] = {i, j};\n                mxr = max(mxr, i);\n                mxc = max(mxc, j);\n            }\n            fields[k].h = mxr + 1;\n            fields[k].w = mxc + 1;\n            totalArea += d;\n        }\n\n        cellObs.assign(NN, -1);\n        drilledFlag.assign(NN, 0);\n    }\n\n    int ask_set_query(const vector<int> &cells) {\n        cout << \"q \" << cells.size();\n        for (int idx : cells) {\n            cout << ' ' << (idx / N) << ' ' << (idx % N);\n        }\n        cout << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << ' ' << (idx % N) << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    bool answer_mask(const Mask &mask) {\n        vector<int> cells;\n        cells.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) {\n            if (mask_test(mask, idx)) cells.push_back(idx);\n        }\n        cout << \"a \" << cells.size();\n        for (int idx : cells) {\n            cout << ' ' << (idx / N) << ' ' << (idx % N);\n        }\n        cout << '\\n' << flush;\n        int res;\n        cin >> res;\n        ops++;\n        return res == 1;\n    }\n\n    // ---------- preprocessing ----------\n    void build_queries() {\n        // qid layout:\n        // [0, N) row\n        // [N, 2N) col\n        // [2N, 2N+4) mod2\n        // [2N+4, 2N+13) mod3\n        Qall = 2 * N + 13;\n        queryCells.assign(Qall, {});\n        qSize.assign(Qall, 0);\n        qResp.assign(Qall, 0);\n        qKnown.assign(Qall, 0);\n        qScore.assign(Qall, vector<double>(totalArea + 1, 0.0));\n        cellQids.resize(NN);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int idx = i * N + j;\n                int q0 = i;\n                int q1 = N + j;\n                int q2 = 2 * N + (i & 1) * 2 + (j & 1);\n                int q3 = 2 * N + 4 + (i % 3) * 3 + (j % 3);\n                cellQids[idx] = {q0, q1, q2, q3};\n                queryCells[q0].push_back(idx);\n                queryCells[q1].push_back(idx);\n                queryCells[q2].push_back(idx);\n                queryCells[q3].push_back(idx);\n            }\n        }\n        for (int q = 0; q < Qall; q++) qSize[q] = (int)queryCells[q].size();\n    }\n\n    void precompute_placements() {\n        compLog2 = 0.0;\n        for (int k = 0; k < M; k++) {\n            auto &f = fields[k];\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                    mask_clear(p.mask);\n                    p.contrib.fill(0);\n\n                    for (auto [ri, rj] : f.rel) {\n                        int ai = di + ri;\n                        int aj = dj + rj;\n                        int idx = ai * N + aj;\n                        mask_set(p.mask, idx);\n                        auto &arr = cellQids[idx];\n                        for (int t = 0; t < 4; t++) p.contrib[arr[t]]++;\n                    }\n                    f.pls.push_back(p);\n                }\n            }\n            compLog2 += log2((double)max(1, (int)f.pls.size()));\n        }\n    }\n\n    void activate_queries(int l, int r) {\n        for (int q = l; q < r; q++) {\n            if (qKnown[q]) continue;\n            int y = ask_set_query(queryCells[q]);\n            qKnown[q] = 1;\n            qResp[q] = y;\n\n            // variance + rounding robustness\n            double var = qSize[q] * eps * (1.0 - eps) + 0.25;\n            for (int v = 0; v <= totalArea; v++) {\n                double mu = eps * qSize[q] + alpha * v;\n                double diff = y - mu;\n                qScore[q][v] = diff * diff / var;\n            }\n        }\n    }\n\n    // ---------- state ----------\n    State build_state(const vector<int> &choice) {\n        State st;\n        st.choice = choice;\n        st.setsum.fill(0);\n\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[choice[k]];\n            for (int q = 0; q < Qall; q++) st.setsum[q] += pl.contrib[q];\n        }\n\n        st.div = 0.0;\n        for (int q = 0; q < Qall; q++) st.div += qScore[q][st.setsum[q]];\n\n        int D = (int)drilledCells.size();\n        st.drillsum.assign(D, 0);\n        st.pen = 0;\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int s = 0;\n            for (int k = 0; k < M; k++) {\n                s += (int)mask_test(fields[k].pls[choice[k]].mask, idx);\n            }\n            st.drillsum[t] = (short)s;\n            int d = s - drilledObs[t];\n            st.pen += d * d;\n        }\n\n        return st;\n    }\n\n    void apply_move(State &st, int k, int newPid) {\n        int oldPid = st.choice[k];\n        if (oldPid == newPid) return;\n        const auto &oldPl = fields[k].pls[oldPid];\n        const auto &newPl = fields[k].pls[newPid];\n\n        for (int q = 0; q < Qall; q++) {\n            int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n            if (!diff) continue;\n            int oldv = st.setsum[q];\n            int newv = oldv + diff;\n            st.div += qScore[q][newv] - qScore[q][oldv];\n            st.setsum[q] = (short)newv;\n        }\n\n        int D = (int)drilledCells.size();\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n            if (!diff) continue;\n            int oldv = st.drillsum[t];\n            int newv = oldv + diff;\n            int before = oldv - drilledObs[t];\n            int after = newv - drilledObs[t];\n            st.pen += after * after - before * before;\n            st.drillsum[t] = (short)newv;\n        }\n\n        st.choice[k] = newPid;\n    }\n\n    void hill_climb(State &st, int sweeps) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            bool changed = false;\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int kk = 0; kk < M; kk++) {\n                int k = ord[kk];\n                int oldPid = st.choice[k];\n                const auto &oldPl = fields[k].pls[oldPid];\n\n                int bestPid = oldPid;\n                int bestPen = st.pen;\n                double bestDiv = st.div;\n\n                int D = (int)drilledCells.size();\n\n                for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                    if (pid == oldPid) continue;\n                    const auto &newPl = fields[k].pls[pid];\n\n                    int candPen = st.pen;\n                    double candDiv = st.div;\n\n                    for (int q = 0; q < Qall; q++) {\n                        int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n                        if (!diff) continue;\n                        int oldv = st.setsum[q];\n                        int newv = oldv + diff;\n                        candDiv += qScore[q][newv] - qScore[q][oldv];\n                    }\n\n                    for (int t = 0; t < D; t++) {\n                        int idx = drilledCells[t];\n                        int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n                        if (!diff) continue;\n                        int oldv = st.drillsum[t];\n                        int newv = oldv + diff;\n                        int before = oldv - drilledObs[t];\n                        int after = newv - drilledObs[t];\n                        candPen += after * after - before * before;\n                    }\n\n                    if (better(candPen, candDiv, bestPen, bestDiv)) {\n                        bestPen = candPen;\n                        bestDiv = candDiv;\n                        bestPid = pid;\n                    }\n                }\n\n                if (bestPid != oldPid) {\n                    apply_move(st, k, bestPid);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> random_seed() {\n        vector<int> choice(M);\n        for (int k = 0; k < M; k++) choice[k] = rand_int((int)fields[k].pls.size());\n        return choice;\n    }\n\n    vector<int> greedy_seed() {\n        vector<int> choice(M, 0);\n        array<short, MAXQ> cur{};\n        cur.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int id = 0; id < M; id++) {\n            int k = ord[id];\n            int bestPid = 0;\n            double bestDelta = 1e100;\n\n            for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                const auto &pl = fields[k].pls[pid];\n                double delta = 0.0;\n                for (int q = 0; q < Qall; q++) {\n                    int c = pl.contrib[q];\n                    if (!c) continue;\n                    int oldv = cur[q];\n                    int newv = oldv + c;\n                    delta += qScore[q][newv] - qScore[q][oldv];\n                }\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPid = pid;\n                }\n            }\n\n            choice[k] = bestPid;\n            const auto &pl = fields[k].pls[bestPid];\n            for (int q = 0; q < Qall; q++) cur[q] += pl.contrib[q];\n        }\n        return choice;\n    }\n\n    vector<int> perturbed_seed() {\n        if (pool.empty()) return random_seed();\n        int bases = min(4, (int)pool.size());\n        vector<int> choice = pool[rand_int(bases)].choice;\n\n        int changes = 1 + rand_int(max(1, min(4, M)));\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int t = 0; t < changes; t++) {\n            int k = ord[t];\n            int sz = (int)fields[k].pls.size();\n            if (sz <= 1) continue;\n            int cur = choice[k];\n            int np = rand_int(sz - 1);\n            if (np >= cur) np++;\n            choice[k] = np;\n        }\n        return choice;\n    }\n\n    bool contains_choice(const vector<vector<int>> &vv, const vector<int> &x) {\n        for (const auto &v : vv) if (v == x) return true;\n        return false;\n    }\n\n    void optimize_pool(int randomCnt, int pertCnt, int sweeps, bool useGreedy) {\n        vector<vector<int>> seeds;\n\n        for (const auto &st : pool) {\n            if (!contains_choice(seeds, st.choice)) seeds.push_back(st.choice);\n        }\n\n        if (useGreedy) {\n            int g = 6;\n            for (int t = 0; t < g; t++) {\n                auto s = greedy_seed();\n                if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n            }\n        }\n\n        for (int t = 0; t < pertCnt; t++) {\n            auto s = perturbed_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        for (int t = 0; t < randomCnt; t++) {\n            auto s = random_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        if (seeds.empty()) seeds.push_back(random_seed());\n\n        vector<State> cands;\n        cands.reserve(seeds.size());\n        for (auto &seed : seeds) {\n            State st = build_state(seed);\n            hill_climb(st, sweeps);\n            cands.push_back(move(st));\n        }\n\n        sort(cands.begin(), cands.end(), [&](const State &a, const State &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        pool.clear();\n        for (auto &st : cands) {\n            bool dup = false;\n            for (auto &kept : pool) {\n                if (kept.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) pool.push_back(move(st));\n            if ((int)pool.size() >= 24) break;\n        }\n    }\n\n    Mask union_of_choice(const vector<int> &choice) {\n        Mask u{};\n        mask_clear(u);\n        for (int k = 0; k < M; k++) mask_or_eq(u, fields[k].pls[choice[k]].mask);\n        return u;\n    }\n\n    // ---------- drilling ----------\n    void record_drill(int idx, int val) {\n        if (!drilledFlag[idx]) {\n            drilledFlag[idx] = 1;\n            cellObs[idx] = val;\n            drilledCells.push_back(idx);\n            drilledObs.push_back(val);\n        }\n    }\n\n    // ---------- summary ----------\n    UnionSummary summarize_unions() {\n        UnionSummary us;\n        if (pool.empty()) return us;\n\n        us.bestPen = pool[0].pen;\n\n        vector<pair<Mask,double>> items;\n        items.reserve(pool.size());\n\n        int activeQ = max(1, activeQCount());\n\n        // Plausible = exact drill-compatible states (pen == 0), with a div margin.\n        if (us.bestPen == 0) {\n            double bestDiv = 1e100;\n            for (const auto &st : pool) if (st.pen == 0) bestDiv = min(bestDiv, st.div);\n\n            double margin = 2.0 * activeQ + 5.0;\n            for (const auto &st : pool) {\n                if (st.pen != 0) continue;\n                if (st.div <= bestDiv + margin) {\n                    items.push_back({union_of_choice(st.choice), st.div});\n                }\n            }\n            if (!items.empty()) us.hasPlausible = true;\n        }\n\n        // If no plausible pen==0 set, fall back to weighted top states for drill selection only.\n        if (!us.hasPlausible) {\n            double bestObj = 1e100;\n            int take = min(12, (int)pool.size());\n            for (int i = 0; i < take; i++) {\n                double obj = pool[i].div + 10.0 * pool[i].pen;\n                bestObj = min(bestObj, obj);\n            }\n            for (int i = 0; i < take; i++) {\n                double obj = pool[i].div + 10.0 * pool[i].pen;\n                items.push_back({union_of_choice(pool[i].choice), obj});\n            }\n        }\n\n        if (items.empty()) return us;\n\n        double base = 1e100;\n        for (auto &it : items) base = min(base, it.second);\n\n        double temp = us.hasPlausible ? 2.0 : 3.0;\n\n        for (auto &it : items) {\n            double w = exp(-min(50.0, (it.second - base) / temp));\n            int pos = -1;\n            for (int i = 0; i < (int)us.masks.size(); i++) {\n                if (us.masks[i] == it.first) {\n                    pos = i;\n                    break;\n                }\n            }\n            if (pos == -1) {\n                us.masks.push_back(it.first);\n                us.weights.push_back(w);\n            } else {\n                us.weights[pos] += w;\n            }\n        }\n\n        us.distinctUnionCount = (int)us.masks.size();\n\n        double sumW = 0.0;\n        for (double w : us.weights) sumW += w;\n        if (sumW <= 0.0) {\n            sumW = (double)us.weights.size();\n            for (double &w : us.weights) w = 1.0;\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)us.weights.size(); i++) {\n            if (us.weights[i] > us.weights[bestIdx]) bestIdx = i;\n        }\n        us.bestMask = us.masks[bestIdx];\n        us.bestWeight = us.weights[bestIdx] / sumW;\n\n        if (us.hasPlausible) {\n            us.must1 = us.masks[0];\n            us.maybe1 = us.masks[0];\n            for (int i = 1; i < (int)us.masks.size(); i++) {\n                mask_and_eq(us.must1, us.masks[i]);\n                mask_or_eq(us.maybe1, us.masks[i]);\n            }\n\n            for (int idx = 0; idx < NN; idx++) {\n                bool a = mask_test(us.must1, idx);\n                bool b = mask_test(us.maybe1, idx);\n                if (a != b) us.ambiguous.push_back(idx);\n            }\n        }\n\n        vector<double> p(NN, 0.0);\n        for (int u = 0; u < (int)us.masks.size(); u++) {\n            double w = us.weights[u] / sumW;\n            for (int idx = 0; idx < NN; idx++) {\n                if (mask_test(us.masks[u], idx)) p[idx] += w;\n            }\n        }\n\n        us.maxEntropy = -1.0;\n        us.bestCell = -1;\n        for (int idx = 0; idx < NN; idx++) {\n            if (drilledFlag[idx]) continue;\n            double e = p[idx] * (1.0 - p[idx]);\n            if (e > us.maxEntropy + 1e-15) {\n                us.maxEntropy = e;\n                us.bestCell = idx;\n            }\n        }\n\n        return us;\n    }\n\n    Mask consensus_answer_mask(const UnionSummary &us) {\n        Mask ans = us.must1;\n        for (int idx = 0; idx < NN; idx++) {\n            if (cellObs[idx] > 0) mask_set(ans, idx);\n        }\n        return ans;\n    }\n\n    // ---------- finish strategies ----------\n    void full_drill_and_answer() {\n        for (int idx = 0; idx < NN; idx++) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n        Mask ans{};\n        mask_clear(ans);\n        for (int idx = 0; idx < NN; idx++) {\n            if (cellObs[idx] > 0) mask_set(ans, idx);\n        }\n        answer_mask(ans);\n    }\n\n    bool try_answer_strong(double weightThreshold, bool allowEntropy) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n\n        bool ok = false;\n        if (us.distinctUnionCount == 1) ok = true;\n        else if (us.bestWeight >= weightThreshold) ok = true;\n        else if (allowEntropy && us.bestWeight >= 0.90 && us.maxEntropy >= 0.0 && us.maxEntropy < 0.010) ok = true;\n\n        if (!ok) return false;\n\n        if (answer_mask(us.bestMask)) return true;\n        full_drill_and_answer();\n        return true;\n    }\n\n    bool try_small_ambiguous_finish(int limitUndrilled) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (pool.empty() || pool[0].pen != 0) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n        if (need == 0) {\n            if (!us.ambiguous.empty()) return false;\n            Mask ans = consensus_answer_mask(us);\n            if (answer_mask(ans)) return true;\n            full_drill_and_answer();\n            return true;\n        }\n\n        if (need > limitUndrilled) return false;\n        if (ops + need + 1 > maxOps) return false;\n\n        for (int idx : us.ambiguous) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n\n        // Re-optimize under exact drills\n        if (elapsed() < 2.45) optimize_pool(4, 8, 4, false);\n        auto us2 = summarize_unions();\n\n        if (!us2.hasPlausible) return false;\n        if (pool.empty() || pool[0].pen != 0) return false;\n        if (!us2.ambiguous.empty()) return false;\n\n        Mask ans = consensus_answer_mask(us2);\n        if (answer_mask(ans)) return true;\n        full_drill_and_answer();\n        return true;\n    }\n\n    // ---------- main solve ----------\n    void solve() {\n        stTime = chrono::steady_clock::now();\n\n        read_input();\n        build_queries();\n        precompute_placements();\n\n        bool hard = (M >= 9 || compLog2 > 78.0);\n\n        // Stage 1: rows + columns\n        activate_queries(0, 2 * N);\n        optimize_pool(14, 0, 6, true);\n\n        if (try_answer_strong(0.999, false)) return;\n        if (try_small_ambiguous_finish(10)) return;\n\n        auto us = summarize_unions();\n\n        // If it already looks very hard after rows/cols, avoid burning too much extra cost.\n        bool skip_extra_global = false;\n        if (hard && us.distinctUnionCount >= 8 && us.bestWeight < 0.22 && us.maxEntropy > 0.17) {\n            skip_extra_global = true;\n        }\n\n        // Stage 2: mod 2\n        if (!skip_extra_global) {\n            activate_queries(2 * N, 2 * N + 4);\n            optimize_pool(8, 8, 5, false);\n\n            if (try_answer_strong(0.996, false)) return;\n            if (try_small_ambiguous_finish(12)) return;\n\n            us = summarize_unions();\n\n            // If still very ambiguous on a hard case, skip mod3.\n            if (hard && us.distinctUnionCount >= 8 && us.bestWeight < 0.25 && us.maxEntropy > 0.17) {\n                skip_extra_global = true;\n            }\n        }\n\n        // Stage 3: mod 3\n        if (!skip_extra_global) {\n            activate_queries(2 * N + 4, Qall);\n            optimize_pool(8, 10, 5, false);\n\n            if (try_answer_strong(0.990, false)) return;\n            if (try_small_ambiguous_finish(16)) return;\n        }\n\n        int heuristicLimit;\n        if (hard) heuristicLimit = 6;\n        else if (M <= 4) heuristicLimit = 18;\n        else if (M <= 8) heuristicLimit = 12;\n        else heuristicLimit = 8;\n\n        for (int step = 0; step < heuristicLimit; step++) {\n            if (elapsed() > 2.6) break;\n\n            auto cur = summarize_unions();\n\n            double wth = 0.97;\n            if ((int)drilledCells.size() >= 2) wth = 0.95;\n            if ((int)drilledCells.size() >= 4) wth = 0.92;\n\n            if (try_answer_strong(wth, true)) return;\n\n            int ambLimit = min(24, 8 + 2 * step);\n            if (try_small_ambiguous_finish(ambLimit)) return;\n\n            int idx = cur.bestCell;\n            if (idx < 0) break;\n\n            int val = ask_drill(idx);\n            record_drill(idx, val);\n\n            if (elapsed() < 2.5) {\n                optimize_pool(5, 10, 4, false);\n                if (!pool.empty() && pool[0].pen > 0 && elapsed() < 2.25) {\n                    optimize_pool(6, 10, 5, false);\n                }\n            }\n        }\n\n        // One last selective finish attempt\n        if (try_small_ambiguous_finish(24)) return;\n        if (try_answer_strong(0.90, true)) return;\n\n        full_drill_and_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long INF64 = (1LL << 60);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct Solution {\n    long long cost = INF64;\n    vector<vector<Rect>> rects; // [D][N]\n};\n\nstruct CutList {\n    int len = 0;\n    int v[50];\n};\n\nstruct DayRowLayout {\n    int l = 0, r = 0; // [l, r)\n    bool rev = false;\n    CutList cuts;\n};\n\nint D, N;\nvector<vector<int>> a; // [D][N]\n\n// prefW[(h,d,k)] = sum_{t<k} ceil(a[d][t] / h)\nvector<int> prefW;\nint strideK, strideD;\n\ninline int pref_idx(int h, int d, int k) {\n    return h * strideD + d * strideK + k;\n}\ninline int sum_widths(int h, int d, int l, int r) {\n    return prefW[pref_idx(h, d, r)] - prefW[pref_idx(h, d, l)];\n}\ninline int cell_width(int h, int d, int k) {\n    return prefW[pref_idx(h, d, k + 1)] - prefW[pref_idx(h, d, k)];\n}\n\ninline int count_common_arr(const int* A, int nA, const int* B, int nB) {\n    int i = 0, j = 0, c = 0;\n    while (i < nA && j < nB) {\n        if (A[i] == B[j]) {\n            ++c; ++i; ++j;\n        } else if (A[i] < B[j]) {\n            ++i;\n        } else {\n            ++j;\n        }\n    }\n    return c;\n}\n\ninline int count_common_cut(const CutList& A, const CutList& B) {\n    return count_common_arr(A.v, A.len, B.v, B.len);\n}\n\ninline long long dist_cut(const CutList& A, const CutList& B, int h) {\n    int common = count_common_cut(A, B);\n    return 1LL * h * (A.len + B.len - 2 * common);\n}\n\ninline long long dist_cut_arr(const CutList& A, const int* B, int lenB, int h) {\n    int common = count_common_arr(A.v, A.len, B, lenB);\n    return 1LL * h * (A.len + lenB - 2 * common);\n}\n\ninline void build_cuts(int h, int d, int l, int r, bool rev, CutList& out) {\n    out.len = max(0, r - l - 1);\n    int s = 0, p = 0;\n    if (!rev) {\n        for (int k = l; k < r - 1; ++k) {\n            s += cell_width(h, d, k);\n            out.v[p++] = s;\n        }\n    } else {\n        for (int k = r - 1; k > l; --k) {\n            s += cell_width(h, d, k);\n            out.v[p++] = s;\n        }\n    }\n}\n\n// ---------- Exact evaluator ----------\n\nlong long evaluate_exact(const vector<vector<Rect>>& rects) {\n    const int HS = (W - 1) * W;     // horizontal interior segments\n    const int VS = W * (W - 1);     // vertical interior segments\n    const int HWORDS = (HS + 63) >> 6;\n    const int VWORDS = (VS + 63) >> 6;\n\n    vector<uint64_t> prevH(HWORDS, 0), prevV(VWORDS, 0);\n    vector<uint64_t> curH(HWORDS, 0), curV(VWORDS, 0);\n\n    auto setbit = [](vector<uint64_t>& bits, int idx) {\n        bits[idx >> 6] |= (1ULL << (idx & 63));\n    };\n\n    long long cost = 0;\n\n    for (int d = 0; d < D; ++d) {\n        fill(curH.begin(), curH.end(), 0);\n        fill(curV.begin(), curV.end(), 0);\n\n        for (int k = 0; k < N; ++k) {\n            const auto& r = rects[d][k];\n\n            long long area = 1LL * (r.i1 - r.i0) * (r.j1 - r.j0);\n            if (area < a[d][k]) cost += 100LL * (a[d][k] - area);\n\n            if (r.i0 > 0) {\n                int base = (r.i0 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.i1 < W) {\n                int base = (r.i1 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.j0 > 0) {\n                int x = r.j0 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n            if (r.j1 < W) {\n                int x = r.j1 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n        }\n\n        if (d > 0) {\n            for (int i = 0; i < HWORDS; ++i) cost += __builtin_popcountll(prevH[i] ^ curH[i]);\n            for (int i = 0; i < VWORDS; ++i) cost += __builtin_popcountll(prevV[i] ^ curV[i]);\n        }\n\n        prevH.swap(curH);\n        prevV.swap(curV);\n    }\n\n    return cost;\n}\n\n// ---------- Candidate 1: fixed full-width strips ----------\n\nlong long marginal_gain_all_days(int idx, int cur_h) {\n    long long gain = 0;\n    int area = W * cur_h;\n    for (int d = 0; d < D; ++d) {\n        int rem = a[d][idx] - area;\n        if (rem > 0) gain += 100LL * min(W, rem);\n    }\n    return gain;\n}\n\nvector<int> optimize_fixed_strips_all_days() {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>; // gain, idx, current_h\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_all_days(i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            rem = 0;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_all_days(idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_fixed_strips() {\n    Solution sol;\n    vector<int> h = optimize_fixed_strips_all_days();\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Candidate 2: day-by-day strips ----------\n\nlong long marginal_gain_one_day(int d, int idx, int cur_h) {\n    int area = W * cur_h;\n    int rem = a[d][idx] - area;\n    if (rem <= 0) return 0;\n    return 100LL * min(W, rem);\n}\n\nvector<int> optimize_strips_one_day(int d) {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>;\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_one_day(d, i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            rem = 0;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_one_day(d, idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_daily_strips() {\n    Solution sol;\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        vector<int> h = optimize_strips_one_day(d);\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Candidate 3: old row-DP with fixed intervals across all days ----------\n\nstruct RowChoice {\n    int l, r;\n    int h;\n    int last_idx;\n    bool rev;\n};\n\nstruct RowDPResult {\n    Solution sol;\n    vector<int> heights;\n    bool feasible = false;\n};\n\nRowDPResult solve_row_dp_zero_shortage_fixed_intervals() {\n    RowDPResult res;\n    res.sol.cost = INF64;\n\n    auto interval_ok = [&](int l, int r, int h) -> bool {\n        for (int d = 0; d < D; ++d) {\n            if (sum_widths(h, d, l, r) > W) return false;\n        }\n        return true;\n    };\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    vector<vector<long long>> rowCost(N + 1, vector<long long>(N + 1, INF64));\n    vector<vector<int>> bestLast(N + 1, vector<int>(N + 1, -1));\n    vector<vector<char>> bestRev(N + 1, vector<char>(N + 1, 0));\n\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            if (!interval_ok(l, r, W)) continue;\n\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (interval_ok(l, r, mid)) hi = mid;\n                else lo = mid + 1;\n            }\n            int h = lo;\n            reqH[l][r] = h;\n\n            int m = r - l;\n            if (m == 1) {\n                rowCost[l][r] = 0;\n                bestLast[l][r] = l;\n                bestRev[l][r] = 0;\n                continue;\n            }\n\n            long long bestC = INF64;\n            int bestP = l;\n            bool bestR = false;\n\n            int prevCuts[55], curCuts[55];\n            for (int p = l; p < r; ++p) {\n                for (int rev = 0; rev <= 1; ++rev) {\n                    long long total = 0;\n                    int prevLen = 0;\n\n                    for (int d = 0; d < D; ++d) {\n                        int len = 0, s = 0;\n                        if (!rev) {\n                            for (int k = l; k < r; ++k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        } else {\n                            for (int k = r - 1; k >= l; --k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        }\n\n                        if (d > 0) {\n                            int common = count_common_arr(prevCuts, prevLen, curCuts, len);\n                            total += 2LL * h * (len - common);\n                        }\n                        prevLen = len;\n                        for (int i = 0; i < len; ++i) prevCuts[i] = curCuts[i];\n                    }\n\n                    if (total < bestC) {\n                        bestC = total;\n                        bestP = p;\n                        bestR = (bool)rev;\n                    }\n                }\n            }\n\n            rowCost[l][r] = bestC;\n            bestLast[l][r] = bestP;\n            bestRev[l][r] = (char)bestR;\n        }\n    }\n\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, INF64));\n    vector<vector<short>> prvI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> prvH(N + 1, vector<short>(W + 1, -1));\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] >= INF64) continue;\n            for (int j = i + 1; j <= N; ++j) {\n                int h = reqH[i][j];\n                if (h > W || used + h > W) continue;\n                long long nd = dp[i][used] + rowCost[i][j];\n                if (nd < dp[j][used + h]) {\n                    dp[j][used + h] = nd;\n                    prvI[j][used + h] = (short)i;\n                    prvH[j][used + h] = (short)used;\n                }\n            }\n        }\n    }\n\n    int bestUsed = -1;\n    long long bestVal = INF64;\n    for (int used = 0; used <= W; ++used) {\n        if (dp[N][used] < bestVal) {\n            bestVal = dp[N][used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0 || bestVal >= INF64) return res;\n\n    vector<RowChoice> rows;\n    {\n        int ci = N, ch = bestUsed;\n        while (ci > 0) {\n            int pi = prvI[ci][ch];\n            int ph = prvH[ci][ch];\n            RowChoice rc;\n            rc.l = pi;\n            rc.r = ci;\n            rc.h = reqH[pi][ci];\n            rc.last_idx = bestLast[pi][ci];\n            rc.rev = bestRev[pi][ci];\n            rows.push_back(rc);\n            ci = pi;\n            ch = ph;\n        }\n        reverse(rows.begin(), rows.end());\n    }\n\n    res.heights.clear();\n    for (auto& rc : rows) res.heights.push_back(rc.h);\n\n    res.sol.rects.assign(D, vector<Rect>(N));\n    int y = 0;\n    for (const auto& row : rows) {\n        int l = row.l, r = row.r, h = row.h, p = row.last_idx;\n        bool rev = row.rev;\n\n        for (int d = 0; d < D; ++d) {\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r; ++k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            } else {\n                for (int k = r - 1; k >= l; --k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            }\n            res.sol.rects[d][p] = {y, x, y + h, W};\n        }\n        y += h;\n    }\n\n    res.sol.cost = evaluate_exact(res.sol.rects);\n    res.feasible = true;\n    return res;\n}\n\n// ---------- New candidate: fixed row heights, variable intervals per day + local improvement ----------\n\nbool optimize_one_day_for_pattern(\n    int d,\n    const vector<int>& hs,\n    const vector<DayRowLayout>* prevDay,\n    const vector<DayRowLayout>* nextDay,\n    bool useProxy,\n    vector<DayRowLayout>& out\n) {\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return false;\n\n    static long long intervalCost[55][55][55];\n    static unsigned char intervalRev[55][55][55];\n    static long long dp[55][55];\n    static short parL[55][55];\n    static unsigned char parRev[55][55];\n\n    for (int row = 0; row < R; ++row) {\n        int h = hs[row];\n        const CutList* pc = prevDay ? &((*prevDay)[row].cuts) : nullptr;\n        const CutList* nc = nextDay ? &((*nextDay)[row].cuts) : nullptr;\n\n        for (int l = 0; l <= N; ++l) {\n            for (int r = 0; r <= N; ++r) {\n                intervalCost[row][l][r] = INF64;\n                intervalRev[row][l][r] = 0;\n            }\n        }\n\n        for (int l = 0; l < N; ++l) {\n            for (int r = l + 1; r <= N; ++r) {\n                if (sum_widths(h, d, l, r) > W) continue;\n\n                int fcuts[50], rcuts[50];\n                int flen = r - l - 1;\n                int rlen = r - l - 1;\n\n                {\n                    int s = 0, p = 0;\n                    for (int k = l; k < r - 1; ++k) {\n                        s += cell_width(h, d, k);\n                        fcuts[p++] = s;\n                    }\n                }\n                {\n                    int s = 0, p = 0;\n                    for (int k = r - 1; k > l; --k) {\n                        s += cell_width(h, d, k);\n                        rcuts[p++] = s;\n                    }\n                }\n\n                auto calc_cost = [&](const int* cuts, int len) -> long long {\n                    long long c = 0;\n                    if (pc) c += dist_cut_arr(*pc, cuts, len, h);\n                    if (nc) c += dist_cut_arr(*nc, cuts, len, h);\n                    if (!pc && !nc && useProxy) c += 1LL * h * len;\n                    return c;\n                };\n\n                long long c0 = calc_cost(fcuts, flen);\n                long long c1 = calc_cost(rcuts, rlen);\n\n                if (c1 < c0) {\n                    intervalCost[row][l][r] = c1;\n                    intervalRev[row][l][r] = 1;\n                } else {\n                    intervalCost[row][l][r] = c0;\n                    intervalRev[row][l][r] = 0;\n                }\n            }\n        }\n    }\n\n    for (int i = 0; i <= R; ++i) {\n        for (int j = 0; j <= N; ++j) {\n            dp[i][j] = INF64;\n            parL[i][j] = -1;\n            parRev[i][j] = 0;\n        }\n    }\n    dp[0][0] = 0;\n\n    for (int row = 0; row < R; ++row) {\n        for (int l = 0; l <= N; ++l) {\n            if (dp[row][l] >= INF64) continue;\n            int minR = l + 1;\n            int maxR = N - (R - row - 1);\n            for (int r = minR; r <= maxR; ++r) {\n                long long c = intervalCost[row][l][r];\n                if (c >= INF64) continue;\n                long long nd = dp[row][l] + c;\n                if (nd < dp[row + 1][r]) {\n                    dp[row + 1][r] = nd;\n                    parL[row + 1][r] = (short)l;\n                    parRev[row + 1][r] = intervalRev[row][l][r];\n                }\n            }\n        }\n    }\n\n    if (dp[R][N] >= INF64) return false;\n\n    out.assign(R, DayRowLayout{});\n    int cur = N;\n    for (int row = R; row >= 1; --row) {\n        int l = parL[row][cur];\n        bool rev = parRev[row][cur];\n        out[row - 1].l = l;\n        out[row - 1].r = cur;\n        out[row - 1].rev = rev;\n        build_cuts(hs[row - 1], d, l, cur, rev, out[row - 1].cuts);\n        cur = l;\n    }\n    return true;\n}\n\nSolution solve_fixed_height_pattern(const vector<int>& hs) {\n    Solution sol;\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return sol;\n    int sumH = 0;\n    for (int h : hs) {\n        if (h <= 0) return sol;\n        sumH += h;\n    }\n    if (sumH > W) return sol;\n\n    vector<vector<DayRowLayout>> lay(D, vector<DayRowLayout>(R));\n\n    // initial independent layouts\n    for (int d = 0; d < D; ++d) {\n        if (!optimize_one_day_for_pattern(d, hs, nullptr, nullptr, true, lay[d])) {\n            return sol;\n        }\n    }\n\n    // local improvement: coordinate descent on days\n    for (int iter = 0; iter < 2; ++iter) {\n        for (int d = 0; d < D; ++d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, lay[d])) {\n                return sol;\n            }\n        }\n        for (int d = D - 1; d >= 0; --d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, lay[d])) {\n                return sol;\n            }\n        }\n    }\n\n    sol.rects.assign(D, vector<Rect>(N));\n    vector<int> y0(R + 1, 0);\n    for (int r = 0; r < R; ++r) y0[r + 1] = y0[r] + hs[r];\n\n    for (int d = 0; d < D; ++d) {\n        for (int row = 0; row < R; ++row) {\n            int y = y0[row];\n            int h = hs[row];\n            int l = lay[d][row].l;\n            int r = lay[d][row].r;\n            bool rev = lay[d][row].rev;\n\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r - 1; ++k) {\n                    int w = cell_width(h, d, k);\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n                sol.rects[d][r - 1] = {y, x, y + h, W};\n            } else {\n                for (int k = r - 1; k > l; --k) {\n                    int w = cell_width(h, d, k);\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n                sol.rects[d][l] = {y, x, y + h, W};\n            }\n        }\n    }\n\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Single-day min-height pattern (for one representative day) ----------\n\nvector<int> compute_day_minheight_pattern(int dsel) {\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            if (sum_widths(W, dsel, l, r) > W) continue;\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (sum_widths(mid, dsel, l, r) <= W) hi = mid;\n                else lo = mid + 1;\n            }\n            reqH[l][r] = lo;\n        }\n    }\n\n    vector<int> dpH(N + 1, W + 1), dpRows(N + 1, 1e9), parent(N + 1, -1);\n    dpH[0] = 0;\n    dpRows[0] = 0;\n\n    for (int r = 1; r <= N; ++r) {\n        for (int l = 0; l < r; ++l) {\n            if (reqH[l][r] > W || dpH[l] > W) continue;\n            int nh = dpH[l] + reqH[l][r];\n            int nr = dpRows[l] + 1;\n            if (nh < dpH[r] || (nh == dpH[r] && nr < dpRows[r])) {\n                dpH[r] = nh;\n                dpRows[r] = nr;\n                parent[r] = l;\n            }\n        }\n    }\n\n    if (dpH[N] > W) return {};\n\n    vector<int> hs;\n    int cur = N;\n    while (cur > 0) {\n        int l = parent[cur];\n        hs.push_back(reqH[l][cur]);\n        cur = l;\n    }\n    reverse(hs.begin(), hs.end());\n    sort(hs.begin(), hs.end());\n    return hs;\n}\n\n// ---------- Helpers ----------\n\nvector<int> make_equal_heights(int R) {\n    if (R <= 0) return {};\n    vector<int> hs(R, W / R);\n    int rem = W % R;\n    for (int i = 0; i < rem; ++i) hs[R - 1 - i]++;\n    return hs;\n}\n\nvoid consider_best(Solution& best, Solution cand) {\n    if (cand.cost < best.cost) best = std::move(cand);\n}\n\n// ---------- Main ----------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\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    // Precompute prefW\n    strideK = N + 1;\n    strideD = D * strideK;\n    prefW.assign((W + 1) * strideD, 0);\n\n    for (int h = 1; h <= W; ++h) {\n        for (int d = 0; d < D; ++d) {\n            prefW[pref_idx(h, d, 0)] = 0;\n            for (int k = 0; k < N; ++k) {\n                prefW[pref_idx(h, d, k + 1)] = prefW[pref_idx(h, d, k)] + (a[d][k] + h - 1) / h;\n            }\n        }\n    }\n\n    Solution best;\n    best.cost = INF64;\n\n    // Keep simple fallbacks\n    consider_best(best, solve_fixed_strips());\n    consider_best(best, solve_daily_strips());\n\n    // Old fixed-interval row DP\n    RowDPResult rowdp = solve_row_dp_zero_shortage_fixed_intervals();\n    if (rowdp.feasible) consider_best(best, rowdp.sol);\n\n    // Height-pattern candidates for the new solver\n    vector<vector<int>> patterns;\n    auto add_pattern = [&](vector<int> hs) {\n        if (hs.empty()) return;\n        int sumH = 0;\n        for (int h : hs) sumH += h;\n        if (sumH > W) return;\n        if ((int)hs.size() > N) return;\n        patterns.push_back(std::move(hs));\n    };\n\n    // Equal-height shelves\n    for (int R = 1; R <= min(N, 10); ++R) add_pattern(make_equal_heights(R));\n\n    // Heights from old row-DP\n    if (rowdp.feasible) {\n        add_pattern(rowdp.heights);\n        vector<int> hs2 = rowdp.heights;\n        sort(hs2.begin(), hs2.end());\n        add_pattern(hs2);\n    }\n\n    // One representative daily pattern: max total area day\n    int bestDay = 0;\n    long long bestSum = -1;\n    for (int d = 0; d < D; ++d) {\n        long long s = 0;\n        for (int k = 0; k < N; ++k) s += a[d][k];\n        if (s > bestSum) {\n            bestSum = s;\n            bestDay = d;\n        }\n    }\n    add_pattern(compute_day_minheight_pattern(bestDay));\n\n    // Deduplicate exact vectors\n    sort(patterns.begin(), patterns.end());\n    patterns.erase(unique(patterns.begin(), patterns.end()), patterns.end());\n\n    // New strong candidates\n    for (const auto& hs : patterns) {\n        Solution cand = solve_fixed_height_pattern(hs);\n        consider_best(best, std::move(cand));\n    }\n\n    // Output\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            const auto& r = best.rects[d][k];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing i64 = long long;\nusing u32 = uint32_t;\n\nstatic constexpr u32 MOD = 998244353;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 0) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nstruct Op {\n    uint8_t m, p, q;\n    array<uint8_t, 9> idx;\n    array<u32, 9> val;\n};\n\nstruct Solution {\n    array<u32, 81> board{};\n    i64 score = 0;\n    vector<int> used; // list of operation ids; order is irrelevant\n};\n\nstruct Move1 {\n    i64 gain = 0;\n    int type = 0; // 0 none, 1 add, 2 remove, 3 replace\n    int pos = -1;\n    int op = -1;\n};\n\nstruct PairMove {\n    i64 gain = 0;\n    int op1 = -1, op2 = -1;\n};\n\nclass Solver {\npublic:\n    int N, M, K;\n    array<u32, 81> init_board{};\n    i64 init_score = 0;\n    vector<array<array<u32, 3>, 3>> stamps;\n    vector<Op> ops;\n\n    Timer timer;\n    SplitMix64 rng;\n    double END_TIME = 1.88;\n\n    Solver(int N_, int M_, int K_) : N(N_), M(M_), K(K_) {\n        stamps.resize(M);\n    }\n\n    void read_input() {\n        uint64_t seed = 0x123456789abcdef0ULL;\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            for (int j = 0; j < N; j++) {\n                u32 x;\n                cin >> x;\n                init_board[i * N + j] = x;\n                init_score += x;\n                mix_seed(x + 1000003ULL * (i * N + j + 1));\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                    u32 x;\n                    cin >> x;\n                    stamps[m][i][j] = x;\n                    mix_seed(x + 10007ULL * (m + 1) + 1009ULL * i + j);\n                }\n            }\n        }\n\n        rng = SplitMix64(seed);\n        build_ops();\n    }\n\n    void build_ops() {\n        ops.clear();\n        ops.reserve(M * (N - 2) * (N - 2));\n        for (int m = 0; m < M; m++) {\n            for (int p = 0; p <= N - 3; p++) {\n                for (int q = 0; q <= N - 3; q++) {\n                    Op op;\n                    op.m = (uint8_t)m;\n                    op.p = (uint8_t)p;\n                    op.q = (uint8_t)q;\n                    int t = 0;\n                    for (int i = 0; i < 3; i++) {\n                        for (int j = 0; j < 3; j++) {\n                            op.idx[t] = (uint8_t)((p + i) * N + (q + j));\n                            op.val[t] = stamps[m][i][j];\n                            t++;\n                        }\n                    }\n                    ops.push_back(op);\n                }\n            }\n        }\n    }\n\n    inline i64 gain_add(const array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) {\n            u32 x = board[op.idx[k]];\n            u32 s = op.val[k];\n            u32 y = x + s;\n            if (y >= MOD) {\n                g += (i64)y - MOD - x;\n            } else {\n                g += (i64)s;\n            }\n        }\n        return g;\n    }\n\n    inline i64 gain_remove(const array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) {\n            u32 x = board[op.idx[k]];\n            u32 s = op.val[k];\n            if (x >= s) {\n                g -= (i64)s;\n            } else {\n                g += (i64)MOD - s;\n            }\n        }\n        return g;\n    }\n\n    inline void apply_add_board(array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        for (int k = 0; k < 9; k++) {\n            u32& x = board[op.idx[k]];\n            x += op.val[k];\n            if (x >= MOD) x -= MOD;\n        }\n    }\n\n    inline void apply_remove_board(array<u32, 81>& board, int opid) const {\n        const Op& op = ops[opid];\n        for (int k = 0; k < 9; k++) {\n            u32& x = board[op.idx[k]];\n            u32 s = op.val[k];\n            if (x >= s) x -= s;\n            else x = x + MOD - s;\n        }\n    }\n\n    inline void add_op(Solution& sol, int opid) const {\n        i64 g = gain_add(sol.board, opid);\n        sol.score += g;\n        apply_add_board(sol.board, opid);\n        sol.used.push_back(opid);\n    }\n\n    inline void remove_at(Solution& sol, int pos) const {\n        int opid = sol.used[pos];\n        i64 g = gain_remove(sol.board, opid);\n        sol.score += g;\n        apply_remove_board(sol.board, opid);\n        sol.used[pos] = sol.used.back();\n        sol.used.pop_back();\n    }\n\n    inline void replace_at(Solution& sol, int pos, int new_opid) const {\n        int old_opid = sol.used[pos];\n        sol.score += gain_remove(sol.board, old_opid);\n        apply_remove_board(sol.board, old_opid);\n        sol.score += gain_add(sol.board, new_opid);\n        apply_add_board(sol.board, new_opid);\n        sol.used[pos] = new_opid;\n    }\n\n    Solution make_empty_solution() const {\n        Solution s;\n        s.board = init_board;\n        s.score = init_score;\n        s.used.reserve(K);\n        return s;\n    }\n\n    int find_best_add(const array<u32, 81>& board, i64& best_gain) const {\n        best_gain = 0;\n        int best_id = -1;\n        const int O = (int)ops.size();\n        for (int opid = 0; opid < O; opid++) {\n            i64 g = gain_add(board, opid);\n            if (g > best_gain) {\n                best_gain = g;\n                best_id = opid;\n            }\n        }\n        return best_id;\n    }\n\n    int find_best_remove(const Solution& sol, i64& best_gain) const {\n        best_gain = 0;\n        int best_pos = -1;\n        for (int i = 0; i < (int)sol.used.size(); i++) {\n            i64 g = gain_remove(sol.board, sol.used[i]);\n            if (g > best_gain) {\n                best_gain = g;\n                best_pos = i;\n            }\n        }\n        return best_pos;\n    }\n\n    Move1 find_best_move1(const Solution& sol) const {\n        Move1 mv;\n\n        if ((int)sol.used.size() < K) {\n            i64 g_add;\n            int opid = find_best_add(sol.board, g_add);\n            if (g_add > mv.gain) {\n                mv.gain = g_add;\n                mv.type = 1;\n                mv.op = opid;\n            }\n        }\n\n        if (!sol.used.empty()) {\n            i64 g_rem;\n            int pos = find_best_remove(sol, g_rem);\n            if (g_rem > mv.gain) {\n                mv.gain = g_rem;\n                mv.type = 2;\n                mv.pos = pos;\n            }\n\n            // best replace = remove one selected op, then add the best single op\n            array<u32, 81> tmp;\n            for (int i = 0; i < (int)sol.used.size(); i++) {\n                tmp = sol.board;\n                int old_op = sol.used[i];\n                i64 g1 = gain_remove(tmp, old_op);\n                apply_remove_board(tmp, old_op);\n\n                i64 g2;\n                int new_op = find_best_add(tmp, g2);\n                i64 g = g1 + g2;\n                if (new_op != -1 && g > mv.gain) {\n                    mv.gain = g;\n                    mv.type = 3;\n                    mv.pos = i;\n                    mv.op = new_op;\n                }\n            }\n        }\n\n        return mv;\n    }\n\n    PairMove find_best_pair_add(const array<u32, 81>& board) const {\n        PairMove best;\n        const int O = (int)ops.size();\n        array<u32, 81> tmp;\n\n        for (int i = 0; i < O; i++) {\n            tmp = board;\n            i64 g1 = gain_add(tmp, i);\n            apply_add_board(tmp, i);\n\n            for (int j = i; j < O; j++) {\n                i64 g = g1 + gain_add(tmp, j);\n                if (g > best.gain) {\n                    best.gain = g;\n                    best.op1 = i;\n                    best.op2 = j;\n                }\n            }\n        }\n        return best;\n    }\n\n    void hill_climb(Solution& sol) {\n        while (timer.elapsed() < END_TIME) {\n            Move1 mv = find_best_move1(sol);\n\n            if (mv.gain > 0) {\n                if (mv.type == 1) {\n                    add_op(sol, mv.op);\n                } else if (mv.type == 2) {\n                    remove_at(sol, mv.pos);\n                } else if (mv.type == 3) {\n                    replace_at(sol, mv.pos, mv.op);\n                }\n                continue;\n            }\n\n            // Larger neighborhood: add 2 operations together if no 1-move improves.\n            if ((int)sol.used.size() + 2 <= K && timer.elapsed() < END_TIME - 0.02) {\n                PairMove pm = find_best_pair_add(sol.board);\n                if (pm.gain > 0) {\n                    add_op(sol, pm.op1);\n                    add_op(sol, pm.op2);\n                    continue;\n                }\n            }\n\n            break;\n        }\n    }\n\n    static bool cmp_pair_desc(const pair<i64, int>& a, const pair<i64, int>& b) {\n        return a.first > b.first;\n    }\n\n    int choose_rank(int cnt) {\n        int r = 0;\n        while (r + 1 < cnt && rng.next_int(100) < 30) r++;\n        return r;\n    }\n\n    Solution random_construct() {\n        Solution sol = make_empty_solution();\n        const int O = (int)ops.size();\n        const int TOP = 12;\n        vector<pair<i64, int>> cand;\n        cand.reserve(O);\n\n        while ((int)sol.used.size() < K && timer.elapsed() < END_TIME) {\n            cand.clear();\n            for (int opid = 0; opid < O; opid++) {\n                i64 g = gain_add(sol.board, opid);\n                if (g > 0) cand.push_back({g, opid});\n            }\n            if (cand.empty()) break;\n\n            int take = min(TOP, (int)cand.size());\n            nth_element(cand.begin(), cand.begin() + take - 1, cand.end(), cmp_pair_desc);\n            cand.resize(take);\n            sort(cand.begin(), cand.end(), cmp_pair_desc);\n\n            int rank = choose_rank((int)cand.size());\n            add_op(sol, cand[rank].second);\n        }\n\n        return sol;\n    }\n\n    Solution perturb(const Solution& base) {\n        Solution sol = base;\n\n        if (!sol.used.empty()) {\n            int L = (int)sol.used.size();\n            int d;\n            if (rng.next_int(100) < 20) d = 1 + rng.next_int(min(L, 10));\n            else d = 1 + rng.next_int(min(L, 4));\n\n            for (int t = 0; t < d && !sol.used.empty(); t++) {\n                int pos = rng.next_int((int)sol.used.size());\n                remove_at(sol, pos);\n            }\n        }\n\n        // A few random greedy adds to diversify before hill-climbing\n        const int O = (int)ops.size();\n        const int TOP = 6;\n        vector<pair<i64, int>> cand;\n        cand.reserve(O);\n\n        int extra = rng.next_int(4);\n        for (int step = 0; step < extra && (int)sol.used.size() < K && timer.elapsed() < END_TIME; step++) {\n            cand.clear();\n            for (int opid = 0; opid < O; opid++) {\n                i64 g = gain_add(sol.board, opid);\n                if (g > 0) cand.push_back({g, opid});\n            }\n            if (cand.empty()) break;\n\n            int take = min(TOP, (int)cand.size());\n            nth_element(cand.begin(), cand.begin() + take - 1, cand.end(), cmp_pair_desc);\n            cand.resize(take);\n            sort(cand.begin(), cand.end(), cmp_pair_desc);\n\n            int rank = rng.next_int((int)cand.size());\n            add_op(sol, cand[rank].second);\n        }\n\n        return sol;\n    }\n\n    Solution solve() {\n        // Initial deterministic greedy\n        Solution best = make_empty_solution();\n        while ((int)best.used.size() < K && timer.elapsed() < END_TIME) {\n            i64 g;\n            int opid = find_best_add(best.board, g);\n            if (g <= 0) break;\n            add_op(best, opid);\n        }\n        hill_climb(best);\n\n        int iter = 0;\n        while (timer.elapsed() < END_TIME - 0.02) {\n            Solution cur;\n            if (iter < 3 || rng.next_int(100) < 30) {\n                cur = random_construct();\n            } else {\n                cur = perturb(best);\n            }\n            hill_climb(cur);\n            if (cur.score > best.score) {\n                best = std::move(cur);\n            }\n            iter++;\n        }\n\n        return best;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, K;\n    cin >> N >> M >> K;\n\n    Solver solver(N, M, K);\n    solver.read_input();\n    Solution ans = solver.solve();\n\n    cout << ans.used.size() << '\\n';\n    for (int opid : ans.used) {\n        const Op& op = solver.ops[opid];\n        cout << (int)op.m << ' ' << (int)op.p << ' ' << (int)op.q << '\\n';\n    }\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int CNUM = N * N;\n\nstruct Solver {\n    int A[N][N];\n\n    int src_of[CNUM];\n    int pos_of[CNUM];\n\n    int idx[N];                 // next unseen index in each source row\n    bool done[CNUM];\n    int need[N];                // next needed container number for each dispatch row\n\n    // loc_type:\n    // 0 = hidden/in source flow\n    // 1 = buffered on grid\n    // 2 = dispatched\n    int loc_type[CNUM];\n    pair<int,int> buf_pos[CNUM];\n\n    // buffer_occ[r][c] = buffered container id on that cell, -1 if none\n    // We track all cells we use as buffers, including row-side handoff cells (r,3) for r>=1.\n    int buffer_occ[N][N];\n\n    int done_cnt = 0;\n\n    struct Crane {\n        bool alive = true;\n        int r = 0, c = 0;\n        int hold = -1;\n        bool large = false;\n    };\n    Crane cranes[N];\n\n    // actual simulator grid containers\n    int cont[N][N];\n    int arrival_idx[N];\n\n    vector<string> out;\n    int T = 0;\n\n    Solver() {\n        memset(src_of, -1, sizeof(src_of));\n        memset(pos_of, -1, sizeof(pos_of));\n        memset(idx, 0, sizeof(idx));\n        memset(done, 0, sizeof(done));\n        memset(loc_type, 0, sizeof(loc_type));\n        memset(buffer_occ, -1, sizeof(buffer_occ));\n        memset(cont, -1, sizeof(cont));\n        memset(arrival_idx, 0, sizeof(arrival_idx));\n        out.assign(N, \"\");\n    }\n\n    static int mdist(pair<int,int> a, pair<int,int> b) {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    pair<int,int> cur_pos() const {\n        return {cranes[0].r, cranes[0].c};\n    }\n\n    bool assigned_row(int d) const {\n        return d >= 1;\n    }\n\n    void update_need(int d) {\n        while (need[d] <= d * N + (N - 1) && done[need[d]]) need[d]++;\n    }\n\n    bool is_move(char ch) const {\n        return ch == 'U' || ch == 'D' || ch == 'L' || ch == 'R';\n    }\n\n    // Current-needed container on row d is already being handled by small crane.\n    bool row_pending_small(int d) const {\n        if (!assigned_row(d)) return false;\n        int t = need[d];\n        if (t > d * N + (N - 1)) return false;\n        if (cranes[d].hold == t) return true;\n        if (cont[d][3] == t) return true;\n        return false;\n    }\n\n    void mark_done(int id) {\n        if (id < 0 || id >= CNUM) return;\n        if (done[id]) return;\n        done[id] = true;\n        loc_type[id] = 2;\n        done_cnt++;\n        update_need(id / N);\n    }\n\n    void step_sim(const string &act) {\n        // 1. arrivals\n        for (int r = 0; r < N; r++) {\n            if (arrival_idx[r] >= N) continue;\n            if (cont[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (!blocked) {\n                cont[r][0] = A[r][arrival_idx[r]];\n                arrival_idx[r]++;\n            }\n        }\n\n        array<pair<int,int>, N> oldp, newp;\n        for (int i = 0; i < N; i++) {\n            oldp[i] = {cranes[i].r, cranes[i].c};\n            newp[i] = oldp[i];\n        }\n\n        // movement targets\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            char a = act[i];\n            int nr = cranes[i].r, nc = cranes[i].c;\n            if (a == 'U') nr--;\n            if (a == 'D') nr++;\n            if (a == 'L') nc--;\n            if (a == 'R') nc++;\n            if (is_move(a)) {\n                nr = max(0, min(N - 1, nr));\n                nc = max(0, min(N - 1, nc));\n                newp[i] = {nr, nc};\n            }\n        }\n\n        // collision / passing checks (our planner should avoid illegal states)\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            for (int j = i + 1; j < N; j++) {\n                if (!cranes[j].alive) continue;\n                if (act[i] == 'B' || act[j] == 'B') continue;\n                if (newp[i] == newp[j]) {\n                    // should never happen\n                }\n                bool mi = (newp[i] != oldp[i]);\n                bool mj = (newp[j] != oldp[j]);\n                if (mi && mj && newp[i] == oldp[j] && newp[j] == oldp[i]) {\n                    // should never happen\n                }\n            }\n        }\n\n        // bombs\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            if (act[i] == 'B' && cranes[i].hold == -1) {\n                cranes[i].alive = false;\n            }\n        }\n\n        // moves\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            if (is_move(act[i])) {\n                cranes[i].r = newp[i].first;\n                cranes[i].c = newp[i].second;\n            }\n        }\n\n        // pick / drop\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n            if (a == 'P') {\n                if (cranes[i].hold == -1 && cont[r][c] != -1) {\n                    cranes[i].hold = cont[r][c];\n                    cont[r][c] = -1;\n                }\n            } else if (a == 'Q') {\n                if (cranes[i].hold != -1 && cont[r][c] == -1) {\n                    cont[r][c] = cranes[i].hold;\n                    cranes[i].hold = -1;\n                }\n            }\n        }\n\n        // 3. dispatch\n        for (int r = 0; r < N; r++) {\n            if (cont[r][N - 1] != -1) {\n                cont[r][N - 1] = -1;\n            }\n        }\n    }\n\n    char decide_small(int d) const {\n        // first 4 turns: move small cranes to (d,4)\n        if (T < 4) return 'R';\n\n        const Crane &cr = cranes[d];\n\n        if (cr.hold != -1) {\n            if (cr.c == 3) return 'R';\n            if (cr.c == 4) return 'Q';\n            if (cr.c < 4) return 'R';\n            return '.';\n        } else {\n            if (cr.c == 4) {\n                if (cont[d][3] == need[d]) return 'L';\n                return '.';\n            }\n            if (cr.c == 3) {\n                if (cont[d][3] == need[d]) return 'P';\n                return 'R';\n            }\n            if (cr.c < 4) return 'R';\n            return '.';\n        }\n    }\n\n    void emit(char a0) {\n        string act(N, '.');\n        act[0] = a0;\n        for (int i = 1; i < N; i++) act[i] = decide_small(i);\n\n        int small_pick_id[N];\n        int small_q_id[N];\n        for (int i = 0; i < N; i++) {\n            small_pick_id[i] = -1;\n            small_q_id[i] = -1;\n        }\n\n        for (int d = 1; d < N; d++) {\n            if (act[d] == 'P') {\n                small_pick_id[d] = cont[d][3];\n            } else if (act[d] == 'Q') {\n                small_q_id[d] = cranes[d].hold;\n            }\n        }\n\n        for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n        step_sim(act);\n        T++;\n\n        // update planner-side buffer bookkeeping for small cranes\n        for (int d = 1; d < N; d++) {\n            if (small_pick_id[d] != -1) {\n                int id = small_pick_id[d];\n                if (buffer_occ[d][3] == id) buffer_occ[d][3] = -1;\n                if (loc_type[id] == 1) buf_pos[id] = {-1, -1};\n            }\n            if (small_q_id[d] != -1) {\n                mark_done(small_q_id[d]);\n            }\n        }\n    }\n\n    // Route large crane while avoiding vertical travel on columns 3/4.\n    void move_to(int tr, int tc) {\n        int mid = min(tc, 2);\n\n        while (cranes[0].c > mid) emit('L');\n        while (cranes[0].c < mid) emit('R');\n        while (cranes[0].r < tr) emit('D');\n        while (cranes[0].r > tr) emit('U');\n        while (cranes[0].c < tc) emit('R');\n        while (cranes[0].c > tc) emit('L');\n    }\n\n    bool ready_id(int id) const {\n        if (id < 0 || id >= CNUM) return false;\n        if (done[id]) return false;\n        if (loc_type[id] == 1) {\n            return buf_pos[id].first != -1;\n        }\n        int s = src_of[id];\n        return pos_of[id] == idx[s];\n    }\n\n    // Ordinary buffer cells:\n    //   cols 1..2 on all rows,\n    //   plus (0,3),\n    //   plus exhausted source gates (r,0).\n    vector<pair<int,int>> ordinary_slots() const {\n        vector<pair<int,int>> ret;\n        for (int r = 0; r < N; r++) {\n            for (int c = 1; c <= 2; c++) {\n                if (buffer_occ[r][c] == -1) ret.push_back({r, c});\n            }\n        }\n        if (buffer_occ[0][3] == -1) ret.push_back({0, 3});\n        for (int r = 0; r < N; r++) {\n            if (idx[r] == N && buffer_occ[r][0] == -1) {\n                ret.push_back({r, 0});\n            }\n        }\n        return ret;\n    }\n\n    // Overflow slots: row-side handoff cells (r,3) for r=1..4.\n    vector<pair<int,int>> overflow_slots(int exclude_row3 = -1) const {\n        vector<pair<int,int>> ret;\n        for (int r = 1; r < N; r++) {\n            if (r == exclude_row3) continue;\n            if (buffer_occ[r][3] == -1) ret.push_back({r, 3});\n        }\n        return ret;\n    }\n\n    pair<int,int> choose_slot(int src_row, int dest_row, bool allow_overflow = true, int exclude_row3 = -1) const {\n        pair<int,int> best = {-1, -1};\n        int best_score = INT_MAX;\n\n        auto eval = [&](int r, int c, int extra_penalty) {\n            int score = 0;\n            score += abs(src_row - r);\n            score += abs(r - dest_row);\n            score += c;\n            if (r == dest_row) score -= 1;\n            score += extra_penalty;\n            if (score < best_score || (score == best_score && make_pair(r, c) < best)) {\n                best_score = score;\n                best = {r, c};\n            }\n        };\n\n        for (auto [r, c] : ordinary_slots()) eval(r, c, 0);\n        if (allow_overflow) {\n            for (auto [r, c] : overflow_slots(exclude_row3)) eval(r, c, 5);\n        }\n        return best;\n    }\n\n    int choose_ready() const {\n        int best_id = -1;\n        int best_cost = INT_MAX;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (!ready_id(t)) continue;\n\n            pair<int,int> loc;\n            if (loc_type[t] == 1) loc = buf_pos[t];\n            else loc = {src_of[t], 0};\n\n            int cost;\n            if (d == 0) cost = mdist(cp, loc) + abs(loc.first - d) + (4 - loc.second);\n            else cost = mdist(cp, loc) + abs(loc.first - d) + (3 - loc.second);\n\n            if (d > 0 && buffer_occ[d][3] != -1) cost += 6; // may need clearing\n\n            if (cost < best_cost || (cost == best_cost && t < best_id)) {\n                best_cost = cost;\n                best_id = t;\n            }\n        }\n        return best_id;\n    }\n\n    int choose_target_row() const {\n        int best_d = -1;\n        int best_depth = INT_MAX;\n        int best_front = INT_MAX;\n        int best_travel = INT_MAX;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (ready_id(t)) continue;\n\n            int s = src_of[t];\n            int depth = pos_of[t] - idx[s];\n            int front = (idx[s] < N ? A[s][idx[s]] : INT_MAX);\n            int travel = abs(cp.first - s) + cp.second;\n\n            if (depth < best_depth ||\n                (depth == best_depth && front < best_front) ||\n                (depth == best_depth && front == best_front && travel < best_travel) ||\n                (depth == best_depth && front == best_front && travel == best_travel && d < best_d)) {\n                best_depth = depth;\n                best_front = front;\n                best_travel = travel;\n                best_d = d;\n            }\n        }\n        return best_d;\n    }\n\n    void pick_id(int id) {\n        if (loc_type[id] == 1) {\n            auto [r, c] = buf_pos[id];\n            move_to(r, c);\n            emit('P');\n            buffer_occ[r][c] = -1;\n            loc_type[id] = 0;\n            buf_pos[id] = {-1, -1};\n        } else {\n            int s = src_of[id];\n            move_to(s, 0);\n            emit('P');\n            idx[s]++;\n        }\n    }\n\n    void direct_dispatch_large_row0(int id) {\n        move_to(0, 4);\n        emit('Q');\n        mark_done(id);\n    }\n\n    void place_on_row_slot(int id, int d) {\n        // Clear occupied handoff slot if needed.\n        if (buffer_occ[d][3] != -1 && buffer_occ[d][3] != id) {\n            clear_row_slot(d);\n        }\n        move_to(d, 3);\n        emit('Q');\n        loc_type[id] = 1;\n        buf_pos[id] = {d, 3};\n        buffer_occ[d][3] = id;\n    }\n\n    void clear_row_slot(int d) {\n        int x = buffer_occ[d][3];\n        if (x == -1) return;\n        if (x == need[d]) return; // small crane should handle it\n\n        move_to(d, 3);\n        emit('P');\n        buffer_occ[d][3] = -1;\n        loc_type[x] = 0;\n        buf_pos[x] = {-1, -1};\n\n        int y = x / N;\n\n        // Opportunistic immediate handling\n        if (y == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (y > 0 && x == need[y] && !row_pending_small(y) && buffer_occ[y][3] == -1) {\n            place_on_row_slot(x, y);\n            return;\n        }\n\n        auto slot = choose_slot(d, y, true, d);\n        if (slot.first == -1) {\n            // emergency fallback\n            if (y > 0 && y != d && buffer_occ[y][3] == -1) {\n                slot = {y, 3};\n            } else {\n                // try any other overflow row3\n                for (int r = 1; r < N; r++) {\n                    if (r != d && buffer_occ[r][3] == -1) {\n                        slot = {r, 3};\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (slot.first == -1) {\n            // last resort: row0 direct if possible, else put back (should be extremely rare)\n            if (y == 0) {\n                direct_dispatch_large_row0(x);\n                return;\n            } else {\n                move_to(d, 3);\n                emit('Q');\n                loc_type[x] = 1;\n                buf_pos[x] = {d, 3};\n                buffer_occ[d][3] = x;\n                return;\n            }\n        }\n\n        move_to(slot.first, slot.second);\n        emit('Q');\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void dispatch_ready(int id) {\n        pick_id(id);\n        int d = id / N;\n        if (d == 0) {\n            direct_dispatch_large_row0(id);\n        } else {\n            place_on_row_slot(id, d);\n        }\n    }\n\n    void buffer_or_handle_front(int s) {\n        int x = A[s][idx[s]];\n        move_to(s, 0);\n        emit('P');\n        idx[s]++;\n\n        int d = x / N;\n\n        // If this is immediately needed, handle specially.\n        if (d == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (d > 0 && x == need[d] && !row_pending_small(d)) {\n            place_on_row_slot(x, d);\n            return;\n        }\n\n        auto slot = choose_slot(s, d, true, -1);\n\n        if (slot.first == -1) {\n            // emergency fallback\n            if (d == 0) {\n                direct_dispatch_large_row0(x);\n                return;\n            }\n            if (buffer_occ[d][3] == -1) {\n                slot = {d, 3};\n            } else {\n                for (int r = 1; r < N; r++) {\n                    if (buffer_occ[r][3] == -1) {\n                        slot = {r, 3};\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (slot.first == -1) {\n            // extremely rare worst-case fallback\n            if (d == 0) {\n                direct_dispatch_large_row0(x);\n                return;\n            } else {\n                // clear own row slot and use it\n                clear_row_slot(d);\n                move_to(d, 3);\n                emit('Q');\n                loc_type[x] = 1;\n                buf_pos[x] = {d, 3};\n                buffer_occ[d][3] = x;\n                return;\n            }\n        }\n\n        move_to(slot.first, slot.second);\n        emit('Q');\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void solve() {\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int x = A[r][j];\n                src_of[x] = r;\n                pos_of[x] = j;\n            }\n        }\n\n        for (int d = 0; d < N; d++) need[d] = d * N;\n\n        for (int i = 0; i < N; i++) {\n            cranes[i].alive = true;\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].hold = -1;\n            cranes[i].large = (i == 0);\n        }\n\n        // Move small cranes to the dispatch side.\n        for (int k = 0; k < 4; k++) emit('.');\n\n        while (done_cnt < CNUM && T < 10000) {\n            int rdy = choose_ready();\n            if (rdy != -1) {\n                dispatch_ready(rdy);\n                continue;\n            }\n\n            int d = choose_target_row();\n            if (d == -1) {\n                bool pending = false;\n                for (int r = 1; r < N; r++) {\n                    if (row_pending_small(r)) pending = true;\n                }\n                if (pending) {\n                    if (cranes[0].c > 2) emit('L');\n                    else emit('.');\n                    continue;\n                }\n                break;\n            }\n\n            int t = need[d];\n            int s = src_of[t];\n            buffer_or_handle_front(s);\n        }\n\n        // Drain remaining small-crane deliveries if any.\n        while (done_cnt < CNUM && T < 10000) {\n            bool pending = false;\n            for (int r = 1; r < N; r++) {\n                if (row_pending_small(r)) pending = true;\n            }\n            if (!pending) break;\n            if (cranes[0].c > 2) emit('L');\n            else emit('.');\n        }\n\n        // Safety fallback\n        while (done_cnt < CNUM && T < 10000) {\n            int rdy = choose_ready();\n            if (rdy != -1) {\n                dispatch_ready(rdy);\n                continue;\n            }\n\n            bool progressed = false;\n            for (int s = 0; s < N && !progressed; s++) {\n                if (idx[s] >= N) continue;\n                buffer_or_handle_front(s);\n                progressed = true;\n            }\n            if (progressed) continue;\n\n            bool pending = false;\n            for (int r = 1; r < N; r++) {\n                if (row_pending_small(r)) pending = true;\n            }\n            if (pending) {\n                if (cranes[0].c > 2) emit('L');\n                else emit('.');\n                continue;\n            }\n\n            break;\n        }\n\n        if (out[0].empty()) {\n            for (int i = 0; i < N; i++) out[i] = \".\";\n        }\n\n        for (int i = 0; i < N; i++) {\n            cout << out[i] << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n; // always 5\n    Solver solver;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> solver.A[i][j];\n        }\n    }\n    solver.solve();\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int r, c;\n};\n\nstatic inline int mdist(const Point& a, const Point& b) {\n    return abs(a.r - b.r) + abs(a.c - b.c);\n}\nstatic inline int mdist0(const Point& p) {\n    return p.r + p.c;\n}\n\nPoint apply_sym(Point p, int sym, int N) {\n    // D4: reflect by vertical axis if sym>=4, then rotate sym times.\n    if (sym >= 4) {\n        p.c = N - 1 - p.c;\n        sym -= 4;\n    }\n    for (int k = 0; k < sym; k++) {\n        int nr = p.c;\n        int nc = N - 1 - p.r;\n        p.r = nr;\n        p.c = nc;\n    }\n    return p;\n}\n\nvector<Point> transform_order(const vector<Point>& base, int sym, bool rev, int N) {\n    vector<Point> v;\n    v.reserve(base.size());\n    for (auto p : base) v.push_back(apply_sym(p, sym, N));\n    if (rev) reverse(v.begin(), v.end());\n    return v;\n}\n\nbool validate_order(const vector<Point>& ord, int N, bool cycle) {\n    const int M = N * N;\n    if ((int)ord.size() != M) return false;\n    vector<int> seen(M, 0);\n    for (auto p : ord) {\n        if (p.r < 0 || p.r >= N || p.c < 0 || p.c >= N) return false;\n        int id = p.r * N + p.c;\n        if (seen[id]) return false;\n        seen[id] = 1;\n    }\n    for (int i = 0; i + 1 < M; i++) {\n        if (mdist(ord[i], ord[i + 1]) != 1) return false;\n    }\n    if (cycle && mdist(ord.back(), ord.front()) != 1) return false;\n    return true;\n}\n\nvector<Point> make_base_cycle(int N) {\n    // Even-N Hamiltonian cycle:\n    // down first column,\n    // snake columns 1..N-1 through rows 1..N-1,\n    // then top row back toward column 1.\n    vector<Point> cyc;\n    cyc.reserve(N * N);\n\n    for (int r = 0; r < N; r++) cyc.push_back({r, 0});\n\n    for (int c = 1; c < N; c++) {\n        if (c & 1) {\n            for (int r = N - 1; r >= 1; r--) cyc.push_back({r, c});\n        } else {\n            for (int r = 1; r < N; r++) cyc.push_back({r, c});\n        }\n    }\n\n    cyc.push_back({0, N - 1});\n    for (int c = N - 2; c >= 1; c--) cyc.push_back({0, c});\n\n    return cyc;\n}\n\nvector<Point> make_row_snake(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    for (int r = 0; r < N; r++) {\n        if ((r & 1) == 0) {\n            for (int c = 0; c < N; c++) ord.push_back({r, c});\n        } else {\n            for (int c = N - 1; c >= 0; c--) ord.push_back({r, c});\n        }\n    }\n    return ord;\n}\n\nvector<Point> make_spiral(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\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++) ord.push_back({top, c});\n        top++;\n        for (int r = top; r <= bottom; r++) ord.push_back({r, right});\n        right--;\n        if (top <= bottom) {\n            for (int c = right; c >= left; c--) ord.push_back({bottom, c});\n            bottom--;\n        }\n        if (left <= right) {\n            for (int r = bottom; r >= top; r--) ord.push_back({r, left});\n            left++;\n        }\n    }\n    return ord;\n}\n\n// Gilbert curve for arbitrary rectangle, used here on 20x20.\n// Good locality, adjacency-preserving path.\nint sgn(int x) { return (x > 0) - (x < 0); }\n\nvoid gilbert2d(int x, int y, int ax, int ay, int bx, int by, vector<Point>& out) {\n    int w = abs(ax + ay);\n    int h = abs(bx + by);\n\n    int dax = sgn(ax), day = sgn(ay);\n    int dbx = sgn(bx), dby = sgn(by);\n\n    if (h == 1) {\n        for (int i = 0; i < w; i++) {\n            out.push_back({y, x});\n            x += dax;\n            y += day;\n        }\n        return;\n    }\n    if (w == 1) {\n        for (int i = 0; i < h; i++) {\n            out.push_back({y, x});\n            x += dbx;\n            y += dby;\n        }\n        return;\n    }\n\n    int ax2 = ax / 2, ay2 = ay / 2;\n    int bx2 = bx / 2, by2 = by / 2;\n\n    int w2 = abs(ax2 + ay2);\n    int h2 = abs(bx2 + by2);\n\n    if (2 * w > 3 * h) {\n        if ((w2 & 1) && (w > 2)) {\n            ax2 += dax;\n            ay2 += day;\n        }\n        gilbert2d(x, y, ax2, ay2, bx, by, out);\n        gilbert2d(x + ax2, y + ay2, ax - ax2, ay - ay2, bx, by, out);\n    } else {\n        if ((h2 & 1) && (h > 2)) {\n            bx2 += dbx;\n            by2 += dby;\n        }\n        gilbert2d(x, y, bx2, by2, ax2, ay2, out);\n        gilbert2d(x + bx2, y + by2, ax, ay, bx - bx2, by - by2, out);\n        gilbert2d(\n            x + (ax - dax) + (bx2 - dbx),\n            y + (ay - day) + (by2 - dby),\n            -bx2, -by2, -(ax - ax2), -(ay - ay2), out\n        );\n    }\n}\n\nvector<Point> make_gilbert(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    gilbert2d(0, 0, N, 0, 0, N, ord);\n    return ord;\n}\n\nstring dir_between(const Point& a, const Point& b) {\n    if (b.r == a.r + 1 && b.c == a.c) return \"D\";\n    if (b.r == a.r - 1 && b.c == a.c) return \"U\";\n    if (b.r == a.r && b.c == a.c + 1) return \"R\";\n    if (b.r == a.r && b.c == a.c - 1) return \"L\";\n    return \"?\";\n}\n\nvoid move_manhattan(Point& cur, const Point& to, vector<string>& ans) {\n    while (cur.r < to.r) ans.push_back(\"D\"), cur.r++;\n    while (cur.r > to.r) ans.push_back(\"U\"), cur.r--;\n    while (cur.c < to.c) ans.push_back(\"R\"), cur.c++;\n    while (cur.c > to.c) ans.push_back(\"L\"), cur.c--;\n}\n\nstruct Best {\n    long long cost = (1LL << 62);\n    vector<Point> order;\n    long long borrow = 0; // extra temporary load at start\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n    vector<vector<int>> h(N, vector<int>(N));\n    long long base = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> h[i][j];\n            base += llabs(h[i][j]);\n        }\n    }\n\n    if (base == 0) {\n        return 0;\n    }\n\n    const int M = N * N;\n\n    vector<Point> cyc0 = make_base_cycle(N);\n    vector<Point> snake0 = make_row_snake(N);\n    vector<Point> spiral0 = make_spiral(N);\n    vector<Point> gilbert0 = make_gilbert(N);\n\n    vector<vector<Point>> base_cycles;\n    vector<vector<Point>> base_paths;\n\n    if (validate_order(cyc0, N, true)) base_cycles.push_back(cyc0);\n    if (validate_order(snake0, N, false)) base_paths.push_back(snake0);\n    if (validate_order(spiral0, N, false)) base_paths.push_back(spiral0);\n    if (validate_order(gilbert0, N, false)) base_paths.push_back(gilbert0);\n\n    Best best;\n\n    auto consider_path = [&](const vector<Point>& ord) {\n        vector<int> a(M);\n        for (int i = 0; i < M; i++) a[i] = h[ord[i].r][ord[i].c];\n\n        long long cur = 0, min_pref = 0, sum_pref = 0;\n        for (int i = 0; i < M; i++) {\n            cur += a[i];\n            min_pref = min(min_pref, cur);\n            if (i + 1 < M) sum_pref += cur;\n        }\n\n        long long k = -min_pref;\n        int retDist = (k > 0 ? mdist(ord.back(), ord.front()) : 0);\n\n        long long cost =\n            base +\n            2LL * k +\n            100LL * (mdist0(ord.front()) + (M - 1) + retDist) +\n            sum_pref +\n            k * 1LL * ((M - 1) + retDist);\n\n        if (cost < best.cost) {\n            best.cost = cost;\n            best.order = ord;\n            best.borrow = k;\n        }\n    };\n\n    auto consider_cycle_all_shifts = [&](const vector<Point>& cyc) {\n        vector<int> a(M);\n        for (int i = 0; i < M; i++) a[i] = h[cyc[i].r][cyc[i].c];\n\n        for (int st = 0; st < M; st++) {\n            long long cur = 0, min_pref = 0, sum_pref = 0;\n            for (int k = 0; k < M; k++) {\n                cur += a[(st + k) % M];\n                min_pref = min(min_pref, cur);\n                if (k + 1 < M) sum_pref += cur;\n            }\n\n            long long borrow = -min_pref;\n            int retDist = (borrow > 0 ? mdist(cyc[(st + M - 1) % M], cyc[st]) : 0); // 1\n\n            long long cost =\n                base +\n                2LL * borrow +\n                100LL * (mdist0(cyc[st]) + (M - 1) + retDist) +\n                sum_pref +\n                borrow * 1LL * ((M - 1) + retDist);\n\n            if (cost < best.cost) {\n                best.cost = cost;\n                best.borrow = borrow;\n                best.order.clear();\n                best.order.reserve(M);\n                for (int i = 0; i < M; i++) best.order.push_back(cyc[(st + i) % M]);\n            }\n        }\n    };\n\n    // Candidate portfolio:\n    // 1) cycle family with all rotations\n    for (auto& base_cyc : base_cycles) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto cyc = transform_order(base_cyc, sym, rev, N);\n                consider_cycle_all_shifts(cyc);\n            }\n        }\n    }\n\n    // 2) several path families\n    for (auto& base_path : base_paths) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto ord = transform_order(base_path, sym, rev, N);\n                consider_path(ord);\n            }\n        }\n    }\n\n    vector<string> ans;\n    ans.reserve(5000);\n\n    Point cur{0, 0};\n    move_manhattan(cur, best.order[0], ans);\n\n    if (best.borrow > 0) {\n        ans.push_back(\"+\" + to_string(best.borrow));\n    }\n\n    for (int i = 0; i < M; i++) {\n        Point p = best.order[i];\n        int v = h[p.r][p.c];\n        if (v > 0) ans.push_back(\"+\" + to_string(v));\n        else if (v < 0) ans.push_back(\"-\" + to_string(-v));\n\n        if (i + 1 < M) {\n            ans.push_back(dir_between(best.order[i], best.order[i + 1]));\n        }\n    }\n\n    cur = best.order.back();\n    if (best.borrow > 0) {\n        move_manhattan(cur, best.order[0], ans);\n        ans.push_back(\"-\" + to_string(best.borrow));\n    }\n\n    for (auto& s : ans) {\n        cout << s << '\\n';\n    }\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Seed {\n    array<int, 15> x{};\n    int value = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, T;\n    int S, P;\n\n    vector<Seed> seeds;\n\n    vector<vector<int>> adj;\n    vector<pair<int, int>> edges;\n    vector<int> deg;\n    vector<int> posOrder;\n    vector<int> blackPos, whitePos;\n\n    mt19937 rng;\n\n    // Per-turn data\n    array<double, 15> rareW{};\n    vector<ll> weightedSeedValue;      // normalized rarity-weighted value\n    vector<vector<int>> evalQ;         // meta-eval edge score (scaled by 100)\n\n    Solver(int N_, int M_, int T_)\n        : N(N_), M(M_), T(T_), S(2 * N_ * (N_ - 1)), P(N_ * N_),\n          rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        buildGrid();\n    }\n\n    void buildGrid() {\n        adj.assign(P, {});\n        deg.assign(P, 0);\n        edges.clear();\n        blackPos.clear();\n        whitePos.clear();\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                if (((r + c) & 1) == 0) blackPos.push_back(p);\n                else whitePos.push_back(p);\n\n                if (c + 1 < N) {\n                    int q = r * N + (c + 1);\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n                if (r + 1 < N) {\n                    int q = (r + 1) * N + c;\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n            }\n        }\n        for (int p = 0; p < P; p++) deg[p] = (int)adj[p].size();\n\n        // center-first, then higher degree first\n        vector<pair<array<int, 5>, int>> ord;\n        ord.reserve(P);\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                int dist = abs(2 * r - (N - 1)) + abs(2 * c - (N - 1));\n                ord.push_back({{dist, -deg[p], ((r + c) & 1), r, c}, p});\n            }\n        }\n        sort(ord.begin(), ord.end());\n        posOrder.clear();\n        for (auto &e : ord) posOrder.push_back(e.second);\n    }\n\n    bool readSeeds() {\n        seeds.assign(S, Seed());\n        for (int i = 0; i < S; i++) {\n            int sum = 0;\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> seeds[i].x[j])) return false;\n                sum += seeds[i].x[j];\n            }\n            seeds[i].value = sum;\n        }\n        return true;\n    }\n\n    // Build rarity weights and evaluation score matrix used for candidate selection\n    void buildTurnStatistics(int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1); // early: 1, late: 0\n\n        array<int, 15> best1{}, best2{}, cntNear{};\n        for (int l = 0; l < M; l++) {\n            int mx1 = -1, mx2 = -1;\n            for (int i = 0; i < S; i++) {\n                int v = seeds[i].x[l];\n                if (v > mx1) {\n                    mx2 = mx1;\n                    mx1 = v;\n                } else if (v > mx2) {\n                    mx2 = v;\n                }\n            }\n            int cnt = 0;\n            for (int i = 0; i < S; i++) {\n                if (seeds[i].x[l] >= mx1 - 1) cnt++;\n            }\n            best1[l] = mx1;\n            best2[l] = max(0, mx2);\n            cntNear[l] = max(1, cnt);\n        }\n\n        double sumW = 0.0;\n        for (int l = 0; l < M; l++) {\n            double scarcity = 1.0 / cntNear[l];\n            double gapRatio = (double)(best1[l] - best2[l]) / max(1, best1[l]);\n            double w = 1.0 + (0.55 * scarcity + 0.90 * gapRatio) * (0.25 + 1.35 * g);\n            rareW[l] = w;\n            sumW += w;\n        }\n        // Normalize so average weight is about 1\n        double norm = (double)M / sumW;\n        for (int l = 0; l < M; l++) rareW[l] *= norm;\n\n        weightedSeedValue.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            double s = 0.0;\n            for (int l = 0; l < M; l++) s += rareW[l] * seeds[i].x[l];\n            weightedSeedValue[i] = (ll)llround(100.0 * s);\n        }\n\n        evalQ.assign(S, vector<int>(S, 0));\n        double betaEval = 1.65 + 0.20 * (1.0 - g); // a bit more top-heavy later\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0;\n                double mean = 0.5 * (seeds[i].value + seeds[j].value);\n                double diff2 = 0.0;\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    opt += max(a, b);\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n                }\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + betaEval * sigma);\n                int v = (int)llround(q * 100.0);\n                evalQ[i][j] = evalQ[j][i] = v;\n            }\n        }\n    }\n\n    vector<vector<ll>> makeScoreMatrix(int scheme, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1); // early 1, late 0\n        double alphaBalanced = 0.25 + 0.45 * g;\n        double alphaRare = 0.35 + 0.40 * g;\n        double beta = 1.45 + 0.30 * (1.0 - g);\n\n        vector<vector<ll>> sc(S, vector<ll>(S, 0));\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0, mean = 0.5 * (seeds[i].value + seeds[j].value), diff2 = 0.0;\n                double optw = 0.0, meanw = 0.0, diffw2 = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    int mx = max(a, b);\n\n                    opt += mx;\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n\n                    optw += rareW[l] * mx;\n                    meanw += 0.5 * rareW[l] * (a + b);\n                    double dw = rareW[l] * d;\n                    diffw2 += dw * dw;\n                }\n\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + beta * sigma);\n\n                double sigmaw = 0.5 * sqrt(diffw2);\n                double qw = min(optw, meanw + beta * sigmaw);\n\n                double val = 0.0;\n                switch (scheme) {\n                    case 0: // balanced\n                        val = alphaBalanced * opt + (1.0 - alphaBalanced) * q;\n                        break;\n                    case 1: // rarity-aware balanced\n                        val = alphaRare * optw + (1.0 - alphaRare) * qw;\n                        break;\n                    case 2: // pure optimistic\n                        val = opt;\n                        break;\n                    case 3: // pure realistic\n                        val = q;\n                        break;\n                    case 4: // rarity-aware realistic\n                        val = qw;\n                        break;\n                    default:\n                        val = q;\n                        break;\n                }\n\n                ll iv = (ll)llround(val * 100.0);\n                sc[i][j] = sc[j][i] = iv;\n            }\n        }\n\n        return sc;\n    }\n\n    vector<ll> computeIndividualPotential(const vector<vector<ll>>& sc, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n        int K = min(5, S - 1);\n\n        vector<ll> ind(S, 0);\n        vector<ll> tmp;\n        tmp.reserve(S - 1);\n\n        for (int i = 0; i < S; i++) {\n            tmp.clear();\n            for (int j = 0; j < S; j++) {\n                if (i == j) continue;\n                tmp.push_back(sc[i][j]);\n            }\n            nth_element(tmp.begin(), tmp.begin() + K, tmp.end(), greater<ll>());\n            ll sumTop = 0;\n            for (int k = 0; k < K; k++) sumTop += tmp[k];\n\n            ll bias = 25LL * seeds[i].value + (ll)llround((12.0 + 18.0 * g) * (weightedSeedValue[i] / 100.0));\n            ind[i] = sumTop / K + bias;\n        }\n        return ind;\n    }\n\n    vector<int> initAssignment(const vector<vector<ll>>& sc, const vector<ll>& ind, int mode, int noiseScale) {\n        vector<int> assign(P, -1);\n        vector<char> used(S, false);\n\n        // mode 1: raw value sort\n        if (mode == 1) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                return weightedSeedValue[a] > weightedSeedValue[b];\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        // mode 2: individual potential sort\n        if (mode == 2) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (ind[a] != ind[b]) return ind[a] > ind[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        // mode 3: coverage-greedy seed selection\n        if (mode == 3) {\n            array<int, 15> bestNow{};\n            bestNow.fill(0);\n\n            for (int idx = 0; idx < P; idx++) {\n                ll bestScore = LLONG_MIN;\n                int bestSeed = -1;\n\n                for (int s = 0; s < S; s++) if (!used[s]) {\n                    ll gain = 0;\n                    for (int l = 0; l < M; l++) {\n                        int v = seeds[s].x[l];\n                        if (v > bestNow[l]) {\n                            gain += (ll)llround(100.0 * rareW[l] * (v - bestNow[l]));\n                        }\n                    }\n                    ll score = gain + weightedSeedValue[s] / 6 + 20LL * seeds[s].value;\n                    if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                    if (score > bestScore || (score == bestScore && (rng() & 1))) {\n                        bestScore = score;\n                        bestSeed = s;\n                    }\n                }\n\n                assign[posOrder[idx]] = bestSeed;\n                used[bestSeed] = true;\n                for (int l = 0; l < M; l++) bestNow[l] = max(bestNow[l], seeds[bestSeed].x[l]);\n            }\n            return assign;\n        }\n\n        // mode 4: weighted value sort\n        if (mode == 4) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (weightedSeedValue[a] != weightedSeedValue[b]) return weightedSeedValue[a] > weightedSeedValue[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        // mode 0 / 5: greedy placement\n        for (int p : posOrder) {\n            int fixedCnt = 0;\n            for (int nb : adj[p]) if (assign[nb] != -1) fixedCnt++;\n\n            ll bestSc = LLONG_MIN;\n            int bestSeed = -1;\n\n            for (int s = 0; s < S; s++) if (!used[s]) {\n                ll score = 1LL * (deg[p] - fixedCnt) * ind[s];\n                for (int nb : adj[p]) {\n                    if (assign[nb] != -1) score += sc[s][assign[nb]];\n                }\n                if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                if (score > bestSc || (score == bestSc && (rng() & 1))) {\n                    bestSc = score;\n                    bestSeed = s;\n                }\n            }\n\n            assign[p] = bestSeed;\n            used[bestSeed] = true;\n        }\n\n        return assign;\n    }\n\n    ll calcObjective(const vector<int>& assign, const vector<vector<ll>>& sc) const {\n        ll res = 0;\n        for (auto [u, v] : edges) res += sc[assign[u]][assign[v]];\n        return res;\n    }\n\n    // Hungarian for maximum weight matching on n x m matrix (n <= m)\n    vector<int> hungarianMax(const vector<vector<ll>>& a) const {\n        int n = (int)a.size();\n        int m = (int)a[0].size();\n        const ll INF = (1LL << 60);\n\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0];\n                int j1 = 0;\n                ll delta = INF;\n\n                for (int j = 1; j <= m; j++) if (!used[j]) {\n                    ll cur = -a[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    void optimizeColor(vector<int>& assign, const vector<vector<ll>>& sc, const vector<int>& group, const vector<int>& other) {\n        vector<char> banned(S, false);\n        for (int p : other) banned[assign[p]] = true;\n\n        vector<int> cand;\n        cand.reserve(S - (int)other.size());\n        for (int s = 0; s < S; s++) if (!banned[s]) cand.push_back(s);\n\n        int n = (int)group.size();\n        int m = (int)cand.size();\n        vector<vector<ll>> benefit(n, vector<ll>(m, 0));\n\n        for (int i = 0; i < n; i++) {\n            int p = group[i];\n            for (int j = 0; j < m; j++) {\n                int s = cand[j];\n                ll b = 0;\n                for (int nb : adj[p]) b += sc[s][assign[nb]];\n                benefit[i][j] = b;\n            }\n        }\n\n        vector<int> choice = hungarianMax(benefit);\n        for (int i = 0; i < n; i++) assign[group[i]] = cand[choice[i]];\n    }\n\n    ll coordinateAscent(vector<int>& assign, const vector<vector<ll>>& sc) {\n        ll obj = calcObjective(assign, sc);\n        for (int it = 0; it < 8; it++) {\n            ll old = obj;\n            optimizeColor(assign, sc, blackPos, whitePos);\n            optimizeColor(assign, sc, whitePos, blackPos);\n            obj = calcObjective(assign, sc);\n            if (obj <= old) break;\n        }\n        return obj;\n    }\n\n    ll deltaSwapCross(const vector<int>& assign, const vector<vector<ll>>& sc, int p, int q) const {\n        int a = assign[p];\n        int b = assign[q];\n        ll d = 0;\n\n        for (int nb : adj[p]) {\n            if (nb == q) continue;\n            d += sc[b][assign[nb]] - sc[a][assign[nb]];\n        }\n        for (int nb : adj[q]) {\n            if (nb == p) continue;\n            d += sc[a][assign[nb]] - sc[b][assign[nb]];\n        }\n        // edge (p,q) itself unchanged because score is symmetric\n        return d;\n    }\n\n    ll crossSwapImprove(vector<int>& assign, const vector<vector<ll>>& sc, ll obj) {\n        for (int pass = 0; pass < 6; pass++) {\n            ll bestDelta = 0;\n            int bp = -1, wq = -1;\n\n            for (int p : blackPos) {\n                for (int q : whitePos) {\n                    ll d = deltaSwapCross(assign, sc, p, q);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bp = p;\n                        wq = q;\n                    }\n                }\n            }\n\n            if (bestDelta <= 0) break;\n            swap(assign[bp], assign[wq]);\n            obj = coordinateAscent(assign, sc);\n        }\n        return obj;\n    }\n\n    ll evaluateCandidate(const vector<int>& assign, int remTurns) const {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n\n        vector<int> qvals;\n        qvals.reserve(edges.size());\n        ll totalQ = 0;\n\n        vector<array<int, 15>> virt(edges.size());\n        array<int, 15> top1{}, top2{}, top3{};\n        top1.fill(0);\n        top2.fill(0);\n        top3.fill(0);\n\n        int ei = 0;\n        for (auto [u, v] : edges) {\n            int a = assign[u], b = assign[v];\n            int q = evalQ[a][b];\n            qvals.push_back(q);\n            totalQ += q;\n\n            for (int l = 0; l < M; l++) {\n                int mv = max(seeds[a].x[l], seeds[b].x[l]);\n                virt[ei][l] = mv;\n                if (mv >= top1[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = top1[l];\n                    top1[l] = mv;\n                } else if (mv >= top2[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = mv;\n                } else if (mv > top3[l]) {\n                    top3[l] = mv;\n                }\n            }\n            ei++;\n        }\n\n        sort(qvals.begin(), qvals.end(), greater<int>());\n        static const int W[10] = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55};\n\n        ll weightedTop = 0;\n        for (int i = 0; i < min<int>(10, qvals.size()); i++) {\n            weightedTop += 1LL * qvals[i] * W[i];\n        }\n        weightedTop /= 100;\n\n        double c2 = 0.45 + 0.25 * g;\n        double c3 = 0.20 * g;\n        double coverage = 0.0;\n        for (int l = 0; l < M; l++) {\n            coverage += top1[l] + c2 * top2[l] + c3 * top3[l];\n        }\n\n        int bestFuture = 0;\n        if (remTurns >= 2) {\n            for (int i = 0; i < (int)virt.size(); i++) {\n                for (int j = i + 1; j < (int)virt.size(); j++) {\n                    int s = 0;\n                    for (int l = 0; l < M; l++) s += max(virt[i][l], virt[j][l]);\n                    if (s > bestFuture) bestFuture = s;\n                }\n            }\n        }\n\n        ll meta = 0;\n        meta += weightedTop;\n        meta += totalQ / 50;\n        meta += (ll)llround((25.0 + 80.0 * g) * coverage);\n        if (remTurns >= 2) meta += (ll)llround((15.0 + 70.0 * g) * bestFuture);\n\n        return meta;\n    }\n\n    vector<int> decideLayout(int turn) {\n        int remTurns = T - turn;\n        buildTurnStatistics(remTurns);\n\n        const int SCHEMES = 5;\n        vector<vector<vector<ll>>> mats;\n        mats.reserve(SCHEMES);\n        for (int s = 0; s < SCHEMES; s++) mats.push_back(makeScoreMatrix(s, remTurns));\n\n        ll bestMeta = LLONG_MIN;\n        vector<int> bestAssign;\n\n        for (int s = 0; s < SCHEMES; s++) {\n            const auto& sc = mats[s];\n            vector<ll> ind = computeIndividualPotential(sc, remTurns);\n\n            // A small ensemble of starts per scheme\n            vector<pair<int, int>> starts = {\n                {0, 0},       // greedy\n                {1, 0},       // value sort\n                {2, 0},       // ind sort\n                {3, 0},       // coverage greedy\n                {4, 0},       // weighted value sort\n                {5, 15000},   // noisy greedy\n            };\n\n            for (auto [mode, noise] : starts) {\n                vector<int> assign = initAssignment(sc, ind, mode, noise);\n                ll obj = coordinateAscent(assign, sc);\n                obj = crossSwapImprove(assign, sc, obj);\n\n                ll meta = evaluateCandidate(assign, remTurns);\n                if (meta > bestMeta) {\n                    bestMeta = meta;\n                    bestAssign = assign;\n                }\n            }\n        }\n\n        return bestAssign;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    Solver solver(N, M, T);\n    if (!solver.readSeeds()) return 0;\n\n    for (int t = 0; t < T; t++) {\n        vector<int> assign = solver.decideLayout(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << assign[i * N + j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (!solver.readSeeds()) return 0;\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Block {\n    bool pickup;           // true: source block, false: target block\n    vector<int> ids;       // indices in src/dst\n};\n\nstruct Plan {\n    int startIdx = 0;\n    int h = 1;\n    long long est = (1LL << 60); // rough estimate\n    string key;\n    vector<Block> blocks;\n};\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nint N, M, Vcap;\nvector<Pt> src, dst;\nint Qm;\nvector<vector<unsigned short>> SS, ST, TS, TT;\nvector<vector<int>> srcIdAt, dstIdAt;\n\nstatic inline int dist_by_type(bool curIsSource, int curIdx, bool toSource, int toIdx) {\n    if (curIsSource) {\n        return toSource ? SS[curIdx][toIdx] : ST[curIdx][toIdx];\n    } else {\n        return toSource ? TS[curIdx][toIdx] : TT[curIdx][toIdx];\n    }\n}\n\nvector<int> make_start_candidates() {\n    vector<int> cand;\n    vector<char> used(Qm, false);\n    auto add = [&](int idx) {\n        if (0 <= idx && idx < Qm && !used[idx]) {\n            used[idx] = true;\n            cand.push_back(idx);\n        }\n    };\n\n    const int ALL_START_THRESHOLD = 180;\n    if (Qm <= ALL_START_THRESHOLD) {\n        for (int i = 0; i < Qm; i++) add(i);\n        return cand;\n    }\n\n    int minX = 0, maxX = 0, minY = 0, maxY = 0;\n    int minS = 0, maxS = 0, minD = 0, maxD = 0;\n    for (int i = 1; i < Qm; i++) {\n        if (src[i].x < src[minX].x) minX = i;\n        if (src[i].x > src[maxX].x) maxX = i;\n        if (src[i].y < src[minY].y) minY = i;\n        if (src[i].y > src[maxY].y) maxY = i;\n        if (src[i].x + src[i].y < src[minS].x + src[minS].y) minS = i;\n        if (src[i].x + src[i].y > src[maxS].x + src[maxS].y) maxS = i;\n        if (src[i].x - src[i].y < src[minD].x - src[minD].y) minD = i;\n        if (src[i].x - src[i].y > src[maxD].x - src[maxD].y) maxD = i;\n    }\n    add(minX); add(maxX); add(minY); add(maxY);\n    add(minS); add(maxS); add(minD); add(maxD);\n\n    vector<Pt> corners = {{0,0}, {0,N-1}, {N-1,0}, {N-1,N-1}};\n    for (auto c : corners) {\n        int best = 0, bestd = manhattan(src[0], c);\n        for (int i = 1; i < Qm; i++) {\n            int d = manhattan(src[i], c);\n            if (d < bestd) bestd = d, best = i;\n        }\n        add(best);\n    }\n\n    double cx = 0, cy = 0;\n    for (auto &p : src) cx += p.x, cy += p.y;\n    cx /= Qm; cy /= Qm;\n    int nearC = 0, farC = 0;\n    double bestNear = 1e100, bestFar = -1.0;\n    for (int i = 0; i < Qm; i++) {\n        double dx = src[i].x - cx;\n        double dy = src[i].y - cy;\n        double v = dx * dx + dy * dy;\n        if (v < bestNear) bestNear = v, nearC = i;\n        if (v > bestFar) bestFar = v, farC = i;\n    }\n    add(nearC); add(farC);\n\n    vector<int> ord(Qm);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int va = src[a].x + src[a].y, vb = src[b].x + src[b].y;\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    add(ord[0]); add(ord[Qm / 4]); add(ord[Qm / 2]); add(ord[(3 * Qm) / 4]); add(ord[Qm - 1]);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int va = src[a].x - src[a].y, vb = src[b].x - src[b].y;\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    add(ord[0]); add(ord[Qm / 4]); add(ord[Qm / 2]); add(ord[(3 * Qm) / 4]); add(ord[Qm - 1]);\n\n    if (cand.empty()) add(0);\n    return cand;\n}\n\nPlan make_batch_plan(int h, int startIdx) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.key = \"B:\" + to_string(h) + \":\" + to_string(startIdx);\n    plan.est = 2;\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    bool curIsSource = true;\n    int curIdx = startIdx;\n    int load = 1;\n\n    while (!remS.empty() || load > 0) {\n        Block b1{true, {}};\n        while (load < h && !remS.empty()) {\n            int bestPos = -1, bestId = -1, bestDist = INT_MAX;\n            for (int pos = 0; pos < (int)remS.size(); pos++) {\n                int id = remS[pos];\n                int d = dist_by_type(curIsSource, curIdx, true, id);\n                if (d < bestDist) {\n                    bestDist = d;\n                    bestPos = pos;\n                    bestId = id;\n                }\n            }\n            plan.est += bestDist;\n            curIsSource = true;\n            curIdx = bestId;\n            load++;\n            b1.ids.push_back(bestId);\n            remS[bestPos] = remS.back();\n            remS.pop_back();\n        }\n        if (!b1.ids.empty()) plan.blocks.push_back(move(b1));\n\n        Block b2{false, {}};\n        while (load > 0) {\n            int bestPos = -1, bestId = -1, bestDist = INT_MAX;\n            for (int pos = 0; pos < (int)remT.size(); pos++) {\n                int id = remT[pos];\n                int d = dist_by_type(curIsSource, curIdx, false, id);\n                if (d < bestDist) {\n                    bestDist = d;\n                    bestPos = pos;\n                    bestId = id;\n                }\n            }\n            plan.est += bestDist;\n            curIsSource = false;\n            curIdx = bestId;\n            load--;\n            b2.ids.push_back(bestId);\n            remT[bestPos] = remT.back();\n            remT.pop_back();\n        }\n        if (!b2.ids.empty()) plan.blocks.push_back(move(b2));\n    }\n    return plan;\n}\n\ntemplate<class DistFunc>\nvector<pair<int,int>> topK_indices(const vector<int>& rem, DistFunc distf, int K) {\n    vector<pair<int,int>> best; // {dist, pos}\n    best.reserve(K);\n    for (int pos = 0; pos < (int)rem.size(); pos++) {\n        int d = distf(rem[pos]);\n        if ((int)best.size() < K) {\n            best.push_back({d, pos});\n            int i = (int)best.size() - 1;\n            while (i > 0 && best[i] < best[i - 1]) {\n                swap(best[i], best[i - 1]);\n                --i;\n            }\n        } else if (d < best.back().first) {\n            best.back() = {d, pos};\n            int i = K - 1;\n            while (i > 0 && best[i] < best[i - 1]) {\n                swap(best[i], best[i - 1]);\n                --i;\n            }\n        }\n    }\n    return best;\n}\n\nint nearest_after_action(bool candIsSource, int candIdx, bool wantSource,\n                         const vector<int>& remS, const vector<int>& remT, int skipId) {\n    int best = INT_MAX;\n    if (wantSource) {\n        for (int id : remS) {\n            if (candIsSource && id == skipId) continue;\n            int d = dist_by_type(candIsSource, candIdx, true, id);\n            if (d < best) best = d;\n        }\n    } else {\n        for (int id : remT) {\n            if (!candIsSource && id == skipId) continue;\n            int d = dist_by_type(candIsSource, candIdx, false, id);\n            if (d < best) best = d;\n        }\n    }\n    return best;\n}\n\nPlan make_balanced_plan(int h, int startIdx, int alpha, int gamma, int topK, int stayBonus) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.key = \"G:\" + to_string(h) + \":\" + to_string(startIdx) + \":\" +\n               to_string(alpha) + \":\" + to_string(gamma) + \":\" + to_string(topK) + \":\" + to_string(stayBonus);\n    plan.est = 2;\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    bool curIsSource = true;\n    int curIdx = startIdx;\n    int load = 1;\n    int prevType = 1; // source\n\n    while (!remS.empty() || load > 0) {\n        vector<tuple<long long,int,int,bool>> cands; // {eval, pos, dist, isSource}\n        cands.reserve(2 * topK);\n\n        if (load < h && !remS.empty()) {\n            auto bestS = topK_indices(remS, [&](int id) {\n                return dist_by_type(curIsSource, curIdx, true, id);\n            }, topK);\n\n            for (auto [d, pos] : bestS) {\n                int id = remS[pos];\n                int load2 = load + 1;\n                int ns = nearest_after_action(true, id, true, remS, remT, id);\n                int nt = nearest_after_action(true, id, false, remS, remT, -1);\n\n                long long future = 0;\n                if (load2 == 0) {\n                    future = (ns == INT_MAX ? 0 : ns);\n                } else if (load2 == h) {\n                    future = (nt == INT_MAX ? 0 : nt);\n                } else {\n                    long long a = (ns == INT_MAX ? (long long)4e18 : (long long)ns + alpha * max(0, 2 * load2 - h));\n                    long long b = (nt == INT_MAX ? (long long)4e18 : (long long)nt + alpha * max(0, h - 2 * load2));\n                    future = min(a, b);\n                    if (future > (long long)3e18) future = 0;\n                }\n                long long eval = (long long)d + (long long)gamma * future;\n                if (prevType == 1) eval -= stayBonus;\n                cands.emplace_back(eval, pos, d, true);\n            }\n        }\n\n        if (load > 0 && !remT.empty()) {\n            auto bestT = topK_indices(remT, [&](int id) {\n                return dist_by_type(curIsSource, curIdx, false, id);\n            }, topK);\n\n            for (auto [d, pos] : bestT) {\n                int id = remT[pos];\n                int load2 = load - 1;\n                int ns = nearest_after_action(false, id, true, remS, remT, -1);\n                int nt = nearest_after_action(false, id, false, remS, remT, id);\n\n                long long future = 0;\n                if (load2 == 0) {\n                    future = (ns == INT_MAX ? 0 : ns);\n                } else if (load2 == h) {\n                    future = (nt == INT_MAX ? 0 : nt);\n                } else {\n                    long long a = (ns == INT_MAX ? (long long)4e18 : (long long)ns + alpha * max(0, 2 * load2 - h));\n                    long long b = (nt == INT_MAX ? (long long)4e18 : (long long)nt + alpha * max(0, h - 2 * load2));\n                    future = min(a, b);\n                    if (future > (long long)3e18) future = 0;\n                }\n                long long eval = (long long)d + (long long)gamma * future;\n                if (prevType == 0) eval -= stayBonus;\n                cands.emplace_back(eval, pos, d, false);\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [&](auto& A, auto& B) {\n            if (get<0>(A) != get<0>(B)) return get<0>(A) < get<0>(B);\n            if (get<2>(A) != get<2>(B)) return get<2>(A) < get<2>(B);\n            return get<3>(A) > get<3>(B);\n        });\n\n        if (cands.empty()) break;\n\n        auto [eval, pos, d, isSource] = cands[0];\n        plan.est += d;\n\n        if (plan.blocks.empty() || plan.blocks.back().pickup != isSource) {\n            plan.blocks.push_back(Block{isSource, {}});\n        }\n\n        if (isSource) {\n            int id = remS[pos];\n            plan.blocks.back().ids.push_back(id);\n            remS[pos] = remS.back();\n            remS.pop_back();\n            curIsSource = true;\n            curIdx = id;\n            load++;\n            prevType = 1;\n        } else {\n            int id = remT[pos];\n            plan.blocks.back().ids.push_back(id);\n            remT[pos] = remT.back();\n            remT.pop_back();\n            curIsSource = false;\n            curIdx = id;\n            load--;\n            prevType = 0;\n        }\n    }\n\n    return plan;\n}\n\nstruct ExecResult {\n    long long cost = (1LL << 60);\n    vector<string> ops;\n};\n\nint path_gain_dp(const Pt& a, const Pt& b, bool pickup, const vector<char>& mark) {\n    static int dp[31][31];\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) dp[i][j] = -1e9;\n    }\n    dp[0][0] = 0;\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && mark[idx]) add = 1;\n            int best = -1e9;\n            if (i > 0) best = max(best, dp[i - 1][j]);\n            if (j > 0) best = max(best, dp[i][j - 1]);\n            dp[i][j] = best + add;\n        }\n    }\n    return dp[dx][dy];\n}\n\nvector<char> reconstruct_best_path(const Pt& a, const Pt& b, bool pickup, const vector<char>& mark) {\n    static int dp[31][31];\n    static char par[31][31];\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            dp[i][j] = -1e9;\n            par[i][j] = '?';\n        }\n    }\n    dp[0][0] = 0;\n    par[0][0] = '.';\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && mark[idx]) add = 1;\n\n            int best = -1e9;\n            char bp = '?';\n            if (i > 0) {\n                int cand = dp[i - 1][j] + add;\n                if (cand > best) best = cand, bp = 'V';\n            }\n            if (j > 0) {\n                int cand = dp[i][j - 1] + add;\n                if (cand > best) best = cand, bp = 'H';\n            }\n            dp[i][j] = best;\n            par[i][j] = bp;\n        }\n    }\n\n    vector<char> rev;\n    int i = dx, j = dy;\n    while (!(i == 0 && j == 0)) {\n        if (par[i][j] == 'V') {\n            rev.push_back(sx == 1 ? 'D' : 'U');\n            --i;\n        } else {\n            rev.push_back(sy == 1 ? 'R' : 'L');\n            --j;\n        }\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nExecResult execute_plan(const Plan& plan, bool buildOps, int Vp, int leafCount) {\n    ExecResult res;\n    if (buildOps) res.ops.clear();\n\n    auto make_cmd = [&]() -> string {\n        return string(2 * Vp, '.');\n    };\n\n    Pt cur = src[plan.startIdx];\n    int load = 1;\n    long long steps = 0;\n\n    vector<int> holding(leafCount, 0);\n    if (leafCount > 0) holding[0] = 1;\n\n    if (buildOps) {\n        string cmd0 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd0[u] = 'R';\n        res.ops.push_back(cmd0);\n\n        string cmd1 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd1[u] = 'R';\n        cmd1[Vp + 2] = 'P';\n        res.ops.push_back(cmd1);\n    }\n\n    for (const auto& block : plan.blocks) {\n        vector<char> mark(Qm, 0);\n        int rem = 0;\n        for (int id : block.ids) {\n            mark[id] = 1;\n            rem++;\n        }\n\n        while (rem > 0) {\n            int bestId = -1;\n            int bestGain = -1;\n            int bestDist = INT_MAX;\n\n            for (int id : block.ids) if (mark[id]) {\n                const Pt& p = block.pickup ? src[id] : dst[id];\n                int g = path_gain_dp(cur, p, block.pickup, mark);\n                int d = manhattan(cur, p);\n                if (g > bestGain || (g == bestGain && d < bestDist)) {\n                    bestGain = g;\n                    bestDist = d;\n                    bestId = id;\n                }\n            }\n\n            const Pt& dest = block.pickup ? src[bestId] : dst[bestId];\n            vector<char> moves = reconstruct_best_path(cur, dest, block.pickup, mark);\n\n            for (char mv : moves) {\n                if (mv == 'U') cur.x--;\n                else if (mv == 'D') cur.x++;\n                else if (mv == 'L') cur.y--;\n                else if (mv == 'R') cur.y++;\n\n                steps++;\n                string cmd;\n                if (buildOps) cmd = make_cmd();\n                if (buildOps) cmd[0] = mv;\n\n                int idx = block.pickup ? srcIdAt[cur.x][cur.y] : dstIdAt[cur.x][cur.y];\n                if (idx != -1 && mark[idx]) {\n                    mark[idx] = 0;\n                    rem--;\n                    if (block.pickup) {\n                        load++;\n                        if (buildOps) {\n                            int chosen = -1;\n                            for (int i = 0; i < leafCount; i++) {\n                                if (!holding[i]) {\n                                    chosen = i;\n                                    holding[i] = 1;\n                                    break;\n                                }\n                            }\n                            if (chosen == -1) chosen = 0;\n                            int vertex = 2 + chosen;\n                            cmd[Vp + vertex] = 'P';\n                        }\n                    } else {\n                        load--;\n                        if (buildOps) {\n                            int chosen = -1;\n                            for (int i = 0; i < leafCount; i++) {\n                                if (holding[i]) {\n                                    chosen = i;\n                                    holding[i] = 0;\n                                    break;\n                                }\n                            }\n                            if (chosen == -1) chosen = 0;\n                            int vertex = 2 + chosen;\n                            cmd[Vp + vertex] = 'P';\n                        }\n                    }\n                }\n\n                if (buildOps) res.ops.push_back(move(cmd));\n            }\n        }\n    }\n\n    if (load != 0) {\n        res.cost = (1LL << 60);\n        return res;\n    }\n    res.cost = 2 + steps;\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> Vcap;\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    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (s[i][j] == '1' && t[i][j] == '0') src.push_back({i, j});\n            else if (s[i][j] == '0' && t[i][j] == '1') dst.push_back({i, j});\n        }\n    }\n\n    Qm = (int)src.size();\n    const int Vp = Vcap;\n    const int leafCount = Vp - 2;\n\n    auto output_tree = [&](int root_x, int root_y) {\n        cout << Vp << '\\n';\n        cout << 0 << ' ' << 1 << '\\n';\n        for (int u = 2; u < Vp; u++) {\n            cout << 1 << ' ' << 1 << '\\n';\n        }\n        cout << root_x << ' ' << root_y << '\\n';\n    };\n\n    if (Qm == 0) {\n        output_tree(0, 0);\n        return 0;\n    }\n\n    SS.assign(Qm, vector<unsigned short>(Qm));\n    ST.assign(Qm, vector<unsigned short>(Qm));\n    TS.assign(Qm, vector<unsigned short>(Qm));\n    TT.assign(Qm, vector<unsigned short>(Qm));\n    for (int i = 0; i < Qm; i++) {\n        for (int j = 0; j < Qm; j++) {\n            SS[i][j] = (unsigned short)manhattan(src[i], src[j]);\n            ST[i][j] = (unsigned short)manhattan(src[i], dst[j]);\n            TS[i][j] = (unsigned short)manhattan(dst[i], src[j]);\n            TT[i][j] = (unsigned short)manhattan(dst[i], dst[j]);\n        }\n    }\n\n    srcIdAt.assign(N, vector<int>(N, -1));\n    dstIdAt.assign(N, vector<int>(N, -1));\n    for (int i = 0; i < Qm; i++) {\n        srcIdAt[src[i].x][src[i].y] = i;\n        dstIdAt[dst[i].x][dst[i].y] = i;\n    }\n\n    vector<int> startCandidates = make_start_candidates();\n    int maxH = min(leafCount, Qm);\n\n    // 1) Generate batch candidates\n    vector<Plan> batchPlans;\n    batchPlans.reserve((int)startCandidates.size() * maxH);\n    for (int h = 1; h <= maxH; h++) {\n        for (int st : startCandidates) {\n            batchPlans.push_back(make_batch_plan(h, st));\n        }\n    }\n    sort(batchPlans.begin(), batchPlans.end(), [](const Plan& a, const Plan& b) {\n        if (a.est != b.est) return a.est < b.est;\n        return a.key < b.key;\n    });\n\n    vector<Plan> finalCandidates;\n    unordered_set<string> usedKey;\n\n    auto add_candidate = [&](const Plan& p) {\n        if (usedKey.insert(p.key).second) finalCandidates.push_back(p);\n    };\n\n    // best batch per h\n    for (int h = 1; h <= maxH; h++) {\n        long long best = (1LL << 60);\n        int bestPos = -1;\n        for (int i = 0; i < (int)batchPlans.size(); i++) {\n            if (batchPlans[i].h == h && batchPlans[i].est < best) {\n                best = batchPlans[i].est;\n                bestPos = i;\n            }\n        }\n        if (bestPos != -1) add_candidate(batchPlans[bestPos]);\n    }\n\n    // top batch overall\n    for (int i = 0; i < min(8, (int)batchPlans.size()); i++) {\n        add_candidate(batchPlans[i]);\n    }\n\n    // 2) Generate balanced candidates from top batch seeds\n    vector<pair<int,int>> seeds; // {start,h}\n    {\n        unordered_set<long long> seen;\n        for (int i = 0; i < min(6, (int)batchPlans.size()); i++) {\n            long long key = (long long)batchPlans[i].startIdx * 100 + batchPlans[i].h;\n            if (seen.insert(key).second) seeds.push_back({batchPlans[i].startIdx, batchPlans[i].h});\n        }\n    }\n\n    vector<Plan> balancedPlans;\n    for (auto [st, h0] : seeds) {\n        vector<int> hs = {h0, max(1, h0 - 1), min(maxH, h0 + 1), maxH, max(1, maxH / 2)};\n        sort(hs.begin(), hs.end());\n        hs.erase(unique(hs.begin(), hs.end()), hs.end());\n        for (int h : hs) {\n            for (int alpha : {0, 2, 4, 8}) {\n                for (int gamma : {0, 1, 2}) {\n                    for (int stayBonus : {0, 2}) {\n                        balancedPlans.push_back(make_balanced_plan(h, st, alpha, gamma, 3, stayBonus));\n                    }\n                }\n            }\n        }\n    }\n    sort(balancedPlans.begin(), balancedPlans.end(), [](const Plan& a, const Plan& b) {\n        if (a.est != b.est) return a.est < b.est;\n        return a.key < b.key;\n    });\n    for (int i = 0; i < min(14, (int)balancedPlans.size()); i++) {\n        add_candidate(balancedPlans[i]);\n    }\n\n    // 3) Exact evaluation with path-aware block optimization\n    long long bestCost = (1LL << 60);\n    int bestIdx = -1;\n\n    vector<long long> exactCost(finalCandidates.size(), (1LL << 60));\n    for (int i = 0; i < (int)finalCandidates.size(); i++) {\n        auto r = execute_plan(finalCandidates[i], false, Vp, leafCount);\n        exactCost[i] = r.cost;\n        if (r.cost < bestCost) {\n            bestCost = r.cost;\n            bestIdx = i;\n        }\n    }\n\n    // Build final ops\n    ExecResult bestRes = execute_plan(finalCandidates[bestIdx], true, Vp, leafCount);\n\n    int root_x = src[finalCandidates[bestIdx].startIdx].x;\n    int root_y = src[finalCandidates[bestIdx].startIdx].y;\n\n    output_tree(root_x, root_y);\n    for (auto &cmd : bestRes.ops) {\n        cout << cmd << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic constexpr int COORD_MAX = 100000;\nstatic constexpr int ENC_SHIFT = 17;\nstatic constexpr int ENC_MASK = (1 << ENC_SHIFT) - 1;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct GridData {\n    int G, sx, sy;\n    int W, H;\n    vector<int> xs, ys;   // boundaries\n    vector<int> w;        // cell weight\n};\n\nstruct Component {\n    vector<int> cells;\n    int prize = 0;\n};\n\nstruct ComponentsResult {\n    vector<Component> comps;\n    vector<int> compId;\n    int bestCid = -1;\n    int positiveCount = 0;\n};\n\nstruct Candidate {\n    vector<Pt> poly;\n    long long approx = 0;\n    int perim = 0;\n    int minx = 0, maxx = 0, miny = 0, maxy = 0;\n    uint64_t hash = 0;\n};\n\nstatic inline long long enc_xy(int x, int y) {\n    return (static_cast<long long>(x) << ENC_SHIFT) | y;\n}\n\nstatic inline Pt dec_xy(long long v) {\n    return Pt{static_cast<int>(v >> ENC_SHIFT), static_cast<int>(v & ENC_MASK)};\n}\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nstatic inline bool between_incl(int v, int a, int b) {\n    if (a > b) swap(a, b);\n    return a <= v && v <= b;\n}\n\nvector<int> create_bounds(int G, int shift) {\n    vector<int> res;\n    res.push_back(0);\n    int cur = 0;\n    if (shift > 0) {\n        res.push_back(shift);\n        cur = shift;\n    }\n    while (cur < COORD_MAX) {\n        cur = min(COORD_MAX, cur + G);\n        if (cur > res.back()) res.push_back(cur);\n    }\n    return res;\n}\n\nint coord_to_index(int v, int G, int shift, int cells) {\n    if (v == COORD_MAX) return cells - 1;\n    if (shift > 0 && v < shift) return 0;\n    int idx;\n    if (shift == 0) idx = v / G;\n    else idx = 1 + (v - shift) / G;\n    if (idx < 0) idx = 0;\n    if (idx >= cells) idx = cells - 1;\n    return idx;\n}\n\nGridData build_grid(const vector<Pt>& macks, const vector<Pt>& sards, int G, int sx, int sy) {\n    GridData gd;\n    gd.G = G; gd.sx = sx; gd.sy = sy;\n    gd.xs = create_bounds(G, sx);\n    gd.ys = create_bounds(G, sy);\n    gd.W = (int)gd.xs.size() - 1;\n    gd.H = (int)gd.ys.size() - 1;\n    gd.w.assign(gd.W * gd.H, 0);\n\n    auto id = [&](int x, int y) { return y * gd.W + x; };\n\n    for (const auto& p : macks) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]++;\n    }\n    for (const auto& p : sards) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]--;\n    }\n    return gd;\n}\n\nlong long region_sum(const vector<char>& occ, const vector<int>& w) {\n    long long s = 0;\n    for (int i = 0; i < (int)occ.size(); i++) if (occ[i]) s += w[i];\n    return s;\n}\n\nvector<char> best_rectangle_region(const GridData& gd) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    long long best = LLONG_MIN;\n    int bestL = -1, bestR = -1, bestB = -1, bestT = -1;\n\n    vector<long long> tmp(H);\n    for (int L = 0; L < W; L++) {\n        fill(tmp.begin(), tmp.end(), 0);\n        for (int R = L; R < W; R++) {\n            for (int y = 0; y < H; y++) tmp[y] += gd.w[id(R, y)];\n            long long cur = 0;\n            int st = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = tmp[y];\n                    st = y;\n                } else {\n                    cur += tmp[y];\n                }\n                if (cur > best) {\n                    best = cur;\n                    bestL = L; bestR = R; bestB = st; bestT = y;\n                }\n            }\n        }\n    }\n\n    vector<char> occ(W * H, 0);\n    if (best <= 0 || bestL < 0) return occ;\n    for (int y = bestB; y <= bestT; y++) {\n        for (int x = bestL; x <= bestR; x++) occ[id(x, y)] = 1;\n    }\n    return occ;\n}\n\nvector<char> graph_cut_select(const GridData& gd, int lambda) {\n    int W = gd.W, H = gd.H;\n    int V = W * H;\n    int S = V, T = V + 1;\n    mf_graph<long long> mf(V + 2);\n\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int ww = gd.w[v];\n            if (ww >= 0) mf.add_edge(S, v, ww);\n            else mf.add_edge(v, T, -ww);\n\n            int border = 0;\n            if (x == 0) border++;\n            if (x == W - 1) border++;\n            if (y == 0) border++;\n            if (y == H - 1) border++;\n            if (border) mf.add_edge(v, T, 1LL * lambda * border);\n\n            if (x + 1 < W) {\n                int u = id(x + 1, y);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n            if (y + 1 < H) {\n                int u = id(x, y + 1);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n        }\n    }\n\n    mf.flow(S, T);\n    auto cut = mf.min_cut(S);\n    vector<char> sel(V, 0);\n    for (int i = 0; i < V; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nComponentsResult get_components(const vector<char>& sel, const vector<int>& w, int W, int H) {\n    ComponentsResult res;\n    int V = W * H;\n    res.compId.assign(V, -1);\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    int cid = 0;\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int s = id(x, y);\n            if (!sel[s] || res.compId[s] != -1) continue;\n\n            queue<int> q;\n            q.push(s);\n            res.compId[s] = cid;\n            Component comp;\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                comp.cells.push_back(v);\n                comp.prize += w[v];\n\n                int vx = v % W, vy = v / W;\n                static const int dx[4] = {1, -1, 0, 0};\n                static const int dy[4] = {0, 0, 1, -1};\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = vx + dx[dir], ny = vy + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (!sel[u] || res.compId[u] != -1) continue;\n                    res.compId[u] = cid;\n                    q.push(u);\n                }\n            }\n\n            res.comps.push_back(std::move(comp));\n            cid++;\n        }\n    }\n\n    int bestPrize = INT_MIN;\n    for (int i = 0; i < (int)res.comps.size(); i++) {\n        if (res.comps[i].prize > 0) {\n            res.positiveCount++;\n            if (res.comps[i].prize > bestPrize) {\n                bestPrize = res.comps[i].prize;\n                res.bestCid = i;\n            }\n        }\n    }\n    return res;\n}\n\nvoid fill_holes(vector<char>& occ, int W, int H) {\n    int PW = W + 2, PH = H + 2;\n    vector<char> vis(PW * PH, 0);\n\n    auto pid = [&](int x, int y) { return y * PW + x; };\n    auto blocked = [&](int x, int y) -> bool {\n        if (x == 0 || x == W + 1 || y == 0 || y == H + 1) return false;\n        return occ[(y - 1) * W + (x - 1)];\n    };\n\n    queue<int> q;\n    q.push(pid(0, 0));\n    vis[pid(0, 0)] = 1;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % PW, y = v / PW;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (nx < 0 || nx >= PW || ny < 0 || ny >= PH) continue;\n            int u = pid(nx, ny);\n            if (vis[u] || blocked(nx, ny)) continue;\n            vis[u] = 1;\n            q.push(u);\n        }\n    }\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = y * W + x;\n            if (!occ[v] && !vis[pid(x + 1, y + 1)]) occ[v] = 1;\n        }\n    }\n}\n\nint count_occ_neighbors(const vector<char>& occ, int v, int W, int H) {\n    int x = v % W, y = v / W;\n    int k = 0;\n    if (x > 0 && occ[v - 1]) k++;\n    if (x + 1 < W && occ[v + 1]) k++;\n    if (y > 0 && occ[v - W]) k++;\n    if (y + 1 < H && occ[v + W]) k++;\n    return k;\n}\n\nbool is_boundary_cell(const vector<char>& occ, int v, int W, int H) {\n    if (!occ[v]) return false;\n    int x = v % W, y = v / W;\n    if (x == 0 || x == W - 1 || y == 0 || y == H - 1) return true;\n    if (!occ[v - 1] || !occ[v + 1] || !occ[v - W] || !occ[v + W]) return true;\n    return false;\n}\n\nbool can_remove_connected(const vector<char>& occ, int rem, int W, int H, int occCount) {\n    if (occCount <= 1) return false;\n    int k = count_occ_neighbors(occ, rem, W, H);\n    if (k <= 1) return true;\n\n    int start = -1;\n    for (int i = 0; i < (int)occ.size(); i++) {\n        if (i != rem && occ[i]) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return false;\n\n    vector<char> vis(occ.size(), 0);\n    queue<int> q;\n    q.push(start);\n    vis[start] = 1;\n    int seen = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (!inside(nx, ny)) continue;\n            int u = id(nx, ny);\n            if (u == rem || !occ[u] || vis[u]) continue;\n            vis[u] = 1;\n            seen++;\n            q.push(u);\n        }\n    }\n    return seen == occCount - 1;\n}\n\nvoid local_hill_climb(vector<char>& occ, const vector<int>& w, int W, int H, int beta) {\n    auto id = [&](int x, int y) { return y * W + x; };\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n\n    int occCount = 0;\n    for (char c : occ) if (c) occCount++;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    for (int pass = 0; pass < 3; pass++) {\n        bool changed = false;\n\n        // Add profitable adjacent cells\n        {\n            vector<pair<int,int>> cand; // (-gain, v)\n            cand.reserve(W * H / 4 + 8);\n            for (int v = 0; v < W * H; v++) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                bool adj = false;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) {\n                        adj = true;\n                        k++;\n                    }\n                }\n                if (!adj) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 50) cand.resize(50);\n\n            for (auto [ng, v] : cand) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) k++;\n                }\n                if (k == 0) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) {\n                    occ[v] = 1;\n                    occCount++;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        // Remove harmful boundary cells\n        {\n            vector<pair<int,int>> cand;\n            cand.reserve(W * H / 4 + 8);\n            for (int v = 0; v < W * H; v++) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 50) cand.resize(50);\n\n            for (auto [ng, v] : cand) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain <= 0) continue;\n                if (can_remove_connected(occ, v, W, H, occCount)) {\n                    occ[v] = 0;\n                    occCount--;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid refine_occ(vector<char>& occ, const vector<int>& w, int W, int H) {\n    fill_holes(occ, W, H);\n    local_hill_climb(occ, w, W, H, 1);\n    local_hill_climb(occ, w, W, H, 2);\n    fill_holes(occ, W, H);\n}\n\nvector<int> top_positive_components(const ComponentsResult& cr, int K) {\n    vector<int> ids;\n    for (int i = 0; i < (int)cr.comps.size(); i++) {\n        if (cr.comps[i].prize > 0) ids.push_back(i);\n    }\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (cr.comps[a].prize != cr.comps[b].prize) return cr.comps[a].prize > cr.comps[b].prize;\n        return cr.comps[a].cells.size() < cr.comps[b].cells.size();\n    });\n    if ((int)ids.size() > K) ids.resize(K);\n    return ids;\n}\n\nvector<char> greedy_connect(\n    const vector<char>& sel,\n    const ComponentsResult& cr,\n    const vector<int>& w,\n    int W, int H,\n    int seedCid\n) {\n    int V = W * H;\n    vector<char> occ(V, 0);\n    if (seedCid < 0 || seedCid >= (int)cr.comps.size()) return occ;\n    if (cr.comps[seedCid].prize <= 0) return occ;\n\n    int C = (int)cr.comps.size();\n    vector<char> goodComp(C, 0);\n    for (int i = 0; i < C; i++) goodComp[i] = (cr.comps[i].prize > 0);\n\n    vector<char> added(C, 0);\n    for (int v : cr.comps[seedCid].cells) occ[v] = 1;\n    added[seedCid] = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    auto is_good_sel = [&](int v) -> bool {\n        if (!sel[v]) return false;\n        int cid = cr.compId[v];\n        return cid >= 0 && goodComp[cid];\n    };\n\n    auto enter_cost = [&](int v) -> int {\n        if (occ[v]) return 0;\n        if (is_good_sel(v)) return 0;\n        int ww = w[v];\n        if (ww >= 2) return 0;\n        if (ww == 1) return 1;\n        if (ww == 0) return 4;\n        return 4 + 6 * (-ww);\n    };\n\n    for (int iter = 0; iter < 12; iter++) {\n        const int INF = 1e9;\n        vector<int> dist(V, INF), parent(V, -1);\n        priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n\n        for (int v = 0; v < V; v++) {\n            if (occ[v]) {\n                dist[v] = 0;\n                pq.push({0, v});\n            }\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            int x = v % W, y = v / W;\n            static const int dx[4] = {1, -1, 0, 0};\n            static const int dy[4] = {0, 0, 1, -1};\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!inside(nx, ny)) continue;\n                int u = id(nx, ny);\n                int nd = d + enter_cost(u);\n                if (nd < dist[u]) {\n                    dist[u] = nd;\n                    parent[u] = v;\n                    pq.push({nd, u});\n                }\n            }\n        }\n\n        long long bestGain = 0;\n        int chooseCid = -1;\n        int chooseCell = -1;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!goodComp[cid] || added[cid]) continue;\n            int bestDist = INF;\n            int bestCell = -1;\n            for (int v : cr.comps[cid].cells) {\n                if (dist[v] < bestDist) {\n                    bestDist = dist[v];\n                    bestCell = v;\n                }\n            }\n            if (bestCell == -1) continue;\n            long long gain = 6LL * cr.comps[cid].prize - bestDist;\n            if (gain > bestGain) {\n                bestGain = gain;\n                chooseCid = cid;\n                chooseCell = bestCell;\n            }\n        }\n\n        if (chooseCid == -1) break;\n\n        vector<char> touched(C, 0);\n        int v = chooseCell;\n        while (v != -1 && !occ[v]) {\n            occ[v] = 1;\n            if (is_good_sel(v)) touched[cr.compId[v]] = 1;\n            v = parent[v];\n        }\n        touched[chooseCid] = 1;\n\n        bool anyNew = false;\n        for (int cid = 0; cid < C; cid++) {\n            if (!touched[cid] || added[cid]) continue;\n            added[cid] = 1;\n            anyNew = true;\n            for (int u : cr.comps[cid].cells) occ[u] = 1;\n        }\n        if (!anyNew) break;\n    }\n\n    return occ;\n}\n\nvector<Pt> build_polygon(const GridData& gd, const vector<char>& occ) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    unordered_map<long long, long long> nxt;\n    nxt.reserve((size_t)occ.size() * 3 + 16);\n    bool bad = false;\n    long long start = -1;\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) {\n        long long a = enc_xy(x1, y1);\n        long long b = enc_xy(x2, y2);\n        auto it = nxt.find(a);\n        if (it != nxt.end() && it->second != b) bad = true;\n        nxt[a] = b;\n        if (start == -1 || a < start) start = a;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            if (!occ[v]) continue;\n            int x0 = gd.xs[x], x1 = gd.xs[x + 1];\n            int y0 = gd.ys[y], y1 = gd.ys[y + 1];\n\n            if (y == 0 || !occ[id(x, y - 1)]) add_edge(x0, y0, x1, y0);\n            if (x == W - 1 || !occ[id(x + 1, y)]) add_edge(x1, y0, x1, y1);\n            if (y == H - 1 || !occ[id(x, y + 1)]) add_edge(x1, y1, x0, y1);\n            if (x == 0 || !occ[id(x - 1, y)]) add_edge(x0, y1, x0, y0);\n        }\n    }\n\n    if (bad || start == -1) return {};\n\n    vector<Pt> poly;\n    long long cur = start;\n    int steps = 0;\n\n    while (true) {\n        poly.push_back(dec_xy(cur));\n        auto it = nxt.find(cur);\n        if (it == nxt.end()) return {};\n        cur = it->second;\n        steps++;\n        if (cur == start) break;\n        if (steps > (int)nxt.size() + 5) return {};\n    }\n\n    if (steps != (int)nxt.size()) return {};\n\n    auto collinear = [&](const Pt& a, const Pt& b, const Pt& c) {\n        return (a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y);\n    };\n\n    bool changed = true;\n    while (changed && (int)poly.size() > 4) {\n        changed = false;\n        vector<Pt> np;\n        int m = (int)poly.size();\n        np.reserve(m);\n        for (int i = 0; i < m; i++) {\n            const Pt& prev = poly[(i - 1 + m) % m];\n            const Pt& curp = poly[i];\n            const Pt& nextp = poly[(i + 1) % m];\n            if (collinear(prev, curp, nextp)) {\n                changed = true;\n            } else {\n                np.push_back(curp);\n            }\n        }\n        poly.swap(np);\n    }\n\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return {};\n\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    for (const auto& p : poly) {\n        long long e = enc_xy(p.x, p.y);\n        if (!seen.insert(e).second) return {};\n    }\n\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        perim += manhattan(poly[i], poly[(i + 1) % poly.size()]);\n    }\n    if (perim > 400000) return {};\n\n    return poly;\n}\n\nuint64_t hash_poly(const vector<Pt>& poly) {\n    uint64_t h = 1469598103934665603ULL;\n    for (const auto& p : poly) {\n        uint64_t v = (uint64_t)p.x * 1000003ULL + (uint64_t)p.y + 0x9e3779b97f4a7c15ULL;\n        h ^= v;\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)poly.size() + 0x517cc1b727220a95ULL;\n    return h;\n}\n\nbool basic_valid_poly(const vector<Pt>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        const auto& a = poly[i];\n        const auto& b = poly[(i + 1) % poly.size()];\n        if (a.x != b.x && a.y != b.y) return false;\n        if (a.x == b.x && a.y == b.y) return false;\n        perim += manhattan(a, b);\n        long long e = enc_xy(a.x, a.y);\n        if (!seen.insert(e).second) return false;\n        if (a.x < 0 || a.x > COORD_MAX || a.y < 0 || a.y > COORD_MAX) return false;\n    }\n    return perim <= 400000;\n}\n\nvector<Pt> snap_poly_lines(const vector<Pt>& poly, const vector<char>& hasX, const vector<char>& hasY) {\n    vector<int> ux, uy;\n    ux.reserve(poly.size());\n    uy.reserve(poly.size());\n    for (auto& p : poly) {\n        ux.push_back(p.x);\n        uy.push_back(p.y);\n    }\n    sort(ux.begin(), ux.end());\n    ux.erase(unique(ux.begin(), ux.end()), ux.end());\n    sort(uy.begin(), uy.end());\n    uy.erase(unique(uy.begin(), uy.end()), uy.end());\n\n    auto snap_axis = [&](const vector<int>& vals, const vector<char>& has) {\n        vector<int> nv = vals;\n        bool changed = false;\n        int K = (int)vals.size();\n        for (int i = 0; i < K; i++) {\n            int L = (i == 0 ? 0 : nv[i - 1] + 1);\n            int R = (i + 1 < K ? vals[i + 1] - 1 : COORD_MAX);\n            if (L > R) {\n                nv[i] = vals[i];\n                continue;\n            }\n            if (!has[vals[i]]) {\n                nv[i] = vals[i];\n                continue;\n            }\n            int best = vals[i];\n            bool found = false;\n            for (int d = 1; d <= max(vals[i] - L, R - vals[i]); d++) {\n                int a = vals[i] - d;\n                if (a >= L && !has[a]) {\n                    best = a;\n                    found = true;\n                    break;\n                }\n                int b = vals[i] + d;\n                if (b <= R && !has[b]) {\n                    best = b;\n                    found = true;\n                    break;\n                }\n            }\n            if (found) {\n                nv[i] = best;\n                if (best != vals[i]) changed = true;\n            } else {\n                nv[i] = vals[i];\n            }\n        }\n        return pair<vector<int>, bool>(nv, changed);\n    };\n\n    auto [nx, cx] = snap_axis(ux, hasX);\n    auto [ny, cy] = snap_axis(uy, hasY);\n    if (!cx && !cy) return {};\n\n    unordered_map<int,int> mx, my;\n    mx.reserve(ux.size() * 2 + 1);\n    my.reserve(uy.size() * 2 + 1);\n    for (int i = 0; i < (int)ux.size(); i++) mx[ux[i]] = nx[i];\n    for (int i = 0; i < (int)uy.size(); i++) my[uy[i]] = ny[i];\n\n    vector<Pt> out = poly;\n    for (auto& p : out) {\n        p.x = mx[p.x];\n        p.y = my[p.y];\n    }\n    if (!basic_valid_poly(out)) return {};\n    return out;\n}\n\nCandidate make_candidate(vector<Pt> poly, long long approx) {\n    Candidate c;\n    c.poly = std::move(poly);\n    c.approx = approx;\n    c.perim = 0;\n    c.minx = c.maxx = c.poly[0].x;\n    c.miny = c.maxy = c.poly[0].y;\n    for (int i = 0; i < (int)c.poly.size(); i++) {\n        c.perim += manhattan(c.poly[i], c.poly[(i + 1) % c.poly.size()]);\n        c.minx = min(c.minx, c.poly[i].x);\n        c.maxx = max(c.maxx, c.poly[i].x);\n        c.miny = min(c.miny, c.poly[i].y);\n        c.maxy = max(c.maxy, c.poly[i].y);\n    }\n    c.hash = hash_poly(c.poly);\n    return c;\n}\n\nvoid try_add_candidate(\n    vector<Candidate>& cands,\n    const GridData& gd,\n    const vector<char>& occ,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    long long approx = region_sum(occ, gd.w);\n    if (approx < 0) return;\n    auto poly = build_polygon(gd, occ);\n    if (poly.empty()) return;\n    cands.push_back(make_candidate(poly, approx));\n\n    auto snapped = snap_poly_lines(poly, hasX, hasY);\n    if (!snapped.empty()) {\n        cands.push_back(make_candidate(snapped, approx));\n    }\n}\n\nbool contains_point(const Candidate& c, const Pt& p) {\n    if (p.x < c.minx || p.x > c.maxx || p.y < c.miny || p.y > c.maxy) return false;\n\n    bool inside = false;\n    int m = (int)c.poly.size();\n    for (int i = 0; i < m; i++) {\n        const Pt& a = c.poly[i];\n        const Pt& b = c.poly[(i + 1) % m];\n\n        if (a.x == b.x) {\n            if (p.x == a.x && between_incl(p.y, a.y, b.y)) return true;\n            if ((a.y > p.y) != (b.y > p.y) && a.x > p.x) inside = !inside;\n        } else {\n            if (p.y == a.y && between_incl(p.x, a.x, b.x)) return true;\n        }\n    }\n    return inside;\n}\n\nint exact_score(const Candidate& c, const vector<pair<Pt,int>>& fishes) {\n    int diff = 0;\n    for (const auto& [p, sgn] : fishes) {\n        if (contains_point(c, p)) diff += sgn;\n    }\n    return max(0, diff + 1);\n}\n\nvector<Pt> find_empty_square(const unordered_set<long long>& pts) {\n    auto has = [&](int x, int y) -> bool {\n        return pts.find(1LL * x * (COORD_MAX + 1) + y) != pts.end();\n    };\n    for (int x = 0; x <= 1000; x++) {\n        for (int y = 0; y <= 1000; y++) {\n            if (x + 1 > COORD_MAX || y + 1 > COORD_MAX) continue;\n            if (!has(x, y) && !has(x + 1, y) && !has(x, y + 1) && !has(x + 1, y + 1)) {\n                return {{x, y}, {x + 1, y}, {x + 1, y + 1}, {x, y + 1}};\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nvoid process_selection(\n    const GridData& gd,\n    const vector<char>& sel,\n    vector<Candidate>& cands,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    auto cr = get_components(sel, gd.w, gd.W, gd.H);\n    auto top = top_positive_components(cr, 3);\n    if (top.empty()) return;\n\n    for (int cid : top) {\n        vector<char> occ(gd.W * gd.H, 0);\n        for (int v : cr.comps[cid].cells) occ[v] = 1;\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, gd, occ2, hasX, hasY);\n    }\n\n    int seeds = min(2, (int)top.size());\n    for (int i = 0; i < seeds; i++) {\n        int cid = top[i];\n        auto occ = greedy_connect(sel, cr, gd.w, gd.W, gd.H, cid);\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, gd, occ2, hasX, hasY);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, std::milli>(chrono::steady_clock::now() - t0).count();\n    };\n\n    int N;\n    cin >> N;\n    vector<Pt> macks(N), sards(N);\n    unordered_set<long long> allPts;\n    allPts.reserve((size_t)2 * N * 2);\n\n    vector<char> hasX(COORD_MAX + 1, 0), hasY(COORD_MAX + 1, 0);\n\n    for (int i = 0; i < N; i++) {\n        cin >> macks[i].x >> macks[i].y;\n        allPts.insert(1LL * macks[i].x * (COORD_MAX + 1) + macks[i].y);\n        hasX[macks[i].x] = 1;\n        hasY[macks[i].y] = 1;\n    }\n    for (int i = 0; i < N; i++) {\n        cin >> sards[i].x >> sards[i].y;\n        allPts.insert(1LL * sards[i].x * (COORD_MAX + 1) + sards[i].y);\n        hasX[sards[i].x] = 1;\n        hasY[sards[i].y] = 1;\n    }\n\n    vector<pair<Pt,int>> fishes;\n    fishes.reserve(2 * N);\n    for (auto& p : macks) fishes.push_back({p, +1});\n    for (auto& p : sards) fishes.push_back({p, -1});\n\n    vector<Candidate> cands;\n    cands.reserve(800);\n\n    vector<int> Gs = {1000, 1400, 1800, 2400, 3200};\n\n    bool stop = false;\n    for (int G : Gs) {\n        vector<pair<int,int>> shifts = {\n            {0, 0},\n            {0, G / 2},\n            {G / 2, 0},\n            {G / 2, G / 2}\n        };\n\n        vector<int> lambdas;\n        if (G == 1000) lambdas = {1};\n        else lambdas = {1, 2};\n\n        for (auto [sx, sy] : shifts) {\n            if (elapsed_ms() > 1500.0) { stop = true; break; }\n\n            GridData gd = build_grid(macks, sards, G, sx, sy);\n\n            // rectangle baseline\n            {\n                auto occ = best_rectangle_region(gd);\n                try_add_candidate(cands, gd, occ, hasX, hasY);\n            }\n\n            // lambda = 0 equivalent: all positive cells\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                for (int i = 0; i < gd.W * gd.H; i++) if (gd.w[i] > 0) sel[i] = 1;\n                process_selection(gd, sel, cands, hasX, hasY);\n            }\n\n            for (int lambda : lambdas) {\n                if (elapsed_ms() > 1600.0) { stop = true; break; }\n                auto sel = graph_cut_select(gd, lambda);\n                process_selection(gd, sel, cands, hasX, hasY);\n            }\n            if (stop) break;\n        }\n        if (stop) break;\n    }\n\n    Candidate best = make_candidate(find_empty_square(allPts), 0);\n    int bestScore = exact_score(best, fishes);\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.perim != b.perim) return a.perim < b.perim;\n        return a.poly.size() < b.poly.size();\n    });\n\n    unordered_set<uint64_t> used;\n    used.reserve(cands.size() * 2 + 16);\n\n    for (const auto& c : cands) {\n        if (elapsed_ms() > 1900.0) break;\n        if (!used.insert(c.hash).second) continue;\n        int sc = exact_score(c, fishes);\n        if (sc > bestScore) {\n            bestScore = sc;\n            best = c;\n        }\n    }\n\n    cout << best.poly.size() << '\\n';\n    for (auto& p : best.poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Dim {\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 baseScore = 1e100;\n    double robustScore = 1e100;\n    uint64_t hash = 0;\n};\n\nstruct ShelfSol {\n    char dir = 'L'; // 'L' = row shelf, 'U' = column shelf\n    vector<unsigned char> used, rot, brk; // if used[i], brk[i]=1 means starts new group among used items\n    double score = 1e100;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstatic uint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    h ^= splitmix64((uint64_t)ops.size());\n    for (const auto& op : ops) {\n        uint64_t v = 0;\n        v ^= (uint64_t)(op.p + 1) * 1000003ULL;\n        v ^= (uint64_t)(op.r + 7) * 10007ULL;\n        v ^= (uint64_t)(unsigned char)(op.d) * 911382323ULL;\n        v ^= (uint64_t)(op.b + 2) * 972663749ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\nstatic bool overlap1D(double l1, double r1, double l2, double r2) {\n    const double EPS = 1e-9;\n    return max(l1, l2) + EPS < min(r1, r2);\n}\n\nstatic double exact_score(const vector<Dim>& dims, const vector<Op>& ops) {\n    int N = (int)dims.size();\n    vector<double> x1(N, 0), y1(N, 0), x2(N, 0), y2(N, 0);\n    vector<char> placed(N, 0), used(N, 0);\n\n    double W = 0, H = 0;\n\n    for (const auto& op : ops) {\n        int p = op.p;\n        double w = op.r ? dims[p].h : dims[p].w;\n        double h = op.r ? dims[p].w : dims[p].h;\n\n        double x = 0, y = 0;\n\n        if (op.d == 'U') {\n            x = (op.b == -1 ? 0.0 : x2[op.b]);\n            y = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(x, x + w, x1[j], x2[j])) {\n                    y = max(y, y2[j]);\n                }\n            }\n        } else {\n            y = (op.b == -1 ? 0.0 : y2[op.b]);\n            x = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(y, y + h, y1[j], y2[j])) {\n                    x = max(x, x2[j]);\n                }\n            }\n        }\n\n        x1[p] = x; y1[p] = y;\n        x2[p] = x + w; y2[p] = y + h;\n        placed[p] = used[p] = 1;\n\n        W = max(W, x2[p]);\n        H = max(H, y2[p]);\n    }\n\n    double penalty = 0.0;\n    for (int i = 0; i < N; i++) {\n        if (!used[i]) penalty += dims[i].w + dims[i].h;\n    }\n    return W + H + penalty;\n}\n\nstatic pair<long long, long long> query_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n\n    long long W, H;\n    if (!(cin >> W >> H)) exit(0);\n    if (W < 0 || H < 0) exit(0);\n    return {W, H};\n}\n\nstatic vector<Op> make_line_ops(const vector<int>& ids, char dir, int rot = 0) {\n    vector<Op> ops;\n    ops.reserve(ids.size());\n    for (int x : ids) ops.push_back({x, rot, dir, -1});\n    return ops;\n}\n\nstatic vector<Op> make_all_line_ops(int N, char dir, int rot = 0) {\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    return make_line_ops(ids, dir, rot);\n}\n\nstatic vector<int> top_k_indices(const vector<double>& vals, int K) {\n    int N = (int)vals.size();\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    nth_element(ids.begin(), ids.begin() + K, ids.end(), [&](int a, int b) {\n        return vals[a] > vals[b];\n    });\n    ids.resize(K);\n    sort(ids.begin(), ids.end());\n    return ids;\n}\n\nstatic vector<double> correct_groupwise(\n    const vector<double>& y,\n    double totalM, double tauTotal,\n    const vector<int>* subset,\n    double subsetM, double tauSubset\n) {\n    int N = (int)y.size();\n    vector<double> x(N);\n    double Sy = 0.0;\n    for (double v : y) Sy += v;\n\n    if (subset == nullptr || subset->empty() || (int)subset->size() == N) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    vector<char> inS(N, 0);\n    double SS = 0.0;\n    for (int idx : *subset) {\n        inS[idx] = 1;\n        SS += y[idx];\n    }\n    double nS = (double)subset->size();\n\n    double d0 = Sy - totalM;\n    double d1 = SS - subsetM;\n\n    double a11 = N + tauTotal;\n    double a12 = nS;\n    double a21 = nS;\n    double a22 = nS + tauSubset;\n    double det = a11 * a22 - a12 * a21;\n    if (fabs(det) < 1e-12) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    double A = (d0 * a22 - d1 * a12) / det;\n    double B = (a11 * d1 - a21 * d0) / det;\n\n    for (int i = 0; i < N; i++) {\n        double v = y[i] - A - (inS[i] ? B : 0.0);\n        x[i] = max(1.0, v);\n    }\n    return x;\n}\n\nstatic inline void get_ab(const Dim& d, char dir, int rot, double& a, double& b) {\n    if (dir == 'L') {\n        // row shelf: a = width, b = height\n        a = rot ? d.h : d.w;\n        b = rot ? d.w : d.h;\n    } else {\n        // column shelf: a = height, b = width\n        a = rot ? d.w : d.h;\n        b = rot ? d.h : d.w;\n    }\n}\n\nstatic inline double metric_b(const Dim& d, char dir, int rot) {\n    if (dir == 'L') return rot ? d.w : d.h;\n    else return rot ? d.h : d.w;\n}\n\nstatic void normalize_shelf(ShelfSol& s) {\n    int N = (int)s.used.size();\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) s.brk[i] = 0;\n    }\n    int first = -1;\n    for (int i = 0; i < N; i++) if (s.used[i]) {\n        first = i;\n        break;\n    }\n    if (first != -1) s.brk[first] = 1;\n}\n\nstatic double shelf_score_fast(const vector<Dim>& dims, const ShelfSol& s) {\n    int N = (int)dims.size();\n    double pen = 0.0;\n    double maxA = 0.0, sumB = 0.0;\n    double curA = 0.0, curB = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) {\n            pen += dims[i].w + dims[i].h;\n            continue;\n        }\n        double a, b;\n        get_ab(dims[i], s.dir, s.rot[i], a, b);\n\n        if (!active || s.brk[i]) {\n            if (active) {\n                maxA = max(maxA, curA);\n                sumB += curB;\n            }\n            curA = a;\n            curB = b;\n            active = true;\n        } else {\n            curA += a;\n            curB = max(curB, b);\n        }\n    }\n    if (active) {\n        maxA = max(maxA, curA);\n        sumB += curB;\n    }\n    return pen + maxA + sumB;\n}\n\nstatic Candidate shelf_to_candidate(const vector<Dim>& base, const ShelfSol& s) {\n    int N = (int)base.size();\n    vector<vector<pair<int,int>>> groups;\n    bool active = false;\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) continue;\n        if (!active || s.brk[i]) {\n            groups.emplace_back();\n            active = true;\n        }\n        groups.back().push_back({i, (int)s.rot[i]});\n    }\n\n    vector<int> reps;\n    reps.reserve(groups.size());\n    for (auto& g : groups) {\n        int bestIdx = g[0].first;\n        double bestM = metric_b(base[g[0].first], s.dir, g[0].second);\n        for (auto [idx, r] : g) {\n            double m = metric_b(base[idx], s.dir, r);\n            if (m > bestM) {\n                bestM = m;\n                bestIdx = idx;\n            }\n        }\n        reps.push_back(bestIdx);\n    }\n\n    vector<Op> ops;\n    for (int gi = 0; gi < (int)groups.size(); gi++) {\n        int bref = (gi == 0 ? -1 : reps[gi - 1]);\n        for (auto [idx, r] : groups[gi]) {\n            ops.push_back({idx, r, s.dir, bref});\n        }\n    }\n\n    Candidate c;\n    c.ops = move(ops);\n    c.baseScore = exact_score(base, c.ops);\n    c.hash = hash_ops(c.ops);\n    return c;\n}\n\nstatic ShelfSol candidate_to_shelf(const Candidate& c, int N) {\n    ShelfSol s;\n    s.dir = c.ops.empty() ? 'L' : c.ops[0].d;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool first = true;\n    int curb = INT_MIN;\n    for (const auto& op : c.ops) {\n        s.used[op.p] = 1;\n        s.rot[op.p] = (unsigned char)op.r;\n        if (first || op.b != curb) {\n            s.brk[op.p] = 1;\n            curb = op.b;\n            first = false;\n        }\n    }\n    normalize_shelf(s);\n    return s;\n}\n\nstatic double total_area(const vector<Dim>& dims) {\n    long double s = 0;\n    for (auto& d : dims) s += (long double)d.w * d.h;\n    return (double)s;\n}\n\nstatic vector<Dim> sample_posterior(\n    const vector<Dim>& base,\n    double sigma,\n    double alpha,\n    double tauW,\n    double tauH,\n    mt19937_64& rng\n) {\n    int N = (int)base.size();\n    static normal_distribution<double> nd(0.0, 1.0);\n\n    vector<double> uw(N), uh(N);\n    double sumUw = 0.0, sumUh = 0.0;\n    for (int i = 0; i < N; i++) {\n        uw[i] = nd(rng) * alpha * sigma;\n        uh[i] = nd(rng) * alpha * sigma;\n        sumUw += uw[i];\n        sumUh += uh[i];\n    }\n\n    double corrW = -sumUw / (N + tauW);\n    double corrH = -sumUh / (N + tauH);\n\n    vector<Dim> out(N);\n    for (int i = 0; i < N; i++) {\n        out[i].w = max(1.0, base[i].w + uw[i] + corrW);\n        out[i].h = max(1.0, base[i].h + uh[i] + corrH);\n    }\n    return out;\n}\n\nstruct Node {\n    int parent = -1;\n    unsigned char act = 0; // 0=skip, 1=continue/start, 2=new group\n    unsigned char rot = 0;\n    double maxDoneA = 0;\n    double sumDoneB = 0;\n    double curA = 0;\n    double curB = 0;\n    double pen = 0;\n    double eval = 0;\n};\n\nstatic inline double node_exact_score(const Node& s) {\n    return s.pen + max(s.maxDoneA, s.curA) + s.sumDoneB + s.curB;\n}\n\nstatic Candidate beam_shelf(\n    const vector<Dim>& sample,\n    const vector<Dim>& base,\n    char dir,\n    double targetA,\n    int beamWidth,\n    double omitMul\n) {\n    int N = (int)sample.size();\n    vector<double> a0(N), b0(N), a1(N), b1(N), remArea(N + 1);\n\n    for (int i = 0; i < N; i++) {\n        double a, b;\n        get_ab(sample[i], dir, 0, a, b);\n        a0[i] = a; b0[i] = b;\n        get_ab(sample[i], dir, 1, a, b);\n        a1[i] = a; b1[i] = b;\n    }\n\n    remArea[N] = 0.0;\n    for (int i = N - 1; i >= 0; i--) {\n        remArea[i] = remArea[i + 1] + sample[i].w * sample[i].h;\n    }\n\n    auto calc_eval = [&](double maxDoneA, double sumDoneB, double curA, double curB, double pen, int nexti) -> double {\n        double nowA = max(maxDoneA, curA);\n        double assumedA = max(nowA, targetA);\n        if (assumedA < 1.0) assumedA = 1.0;\n        return pen + assumedA + sumDoneB + curB + remArea[nexti] / assumedA;\n    };\n\n    vector<Node> nodes;\n    nodes.reserve(1 + (size_t)N * beamWidth * 5 + 16);\n    nodes.push_back(Node());\n    nodes[0].eval = calc_eval(0, 0, 0, 0, 0, 0);\n\n    vector<int> beam, nxt;\n    beam.push_back(0);\n\n    auto cmp = [&](int x, int y) {\n        if (nodes[x].eval != nodes[y].eval) return nodes[x].eval < nodes[y].eval;\n        return node_exact_score(nodes[x]) < node_exact_score(nodes[y]);\n    };\n\n    for (int i = 0; i < N; i++) {\n        nxt.clear();\n        nxt.reserve((size_t)beam.size() * 5 + 8);\n\n        for (int id : beam) {\n            const Node& s = nodes[id];\n\n            {\n                Node t = s;\n                t.parent = id;\n                t.act = 0;\n                t.rot = 0;\n                t.pen = s.pen + omitMul * (sample[i].w + sample[i].h);\n                t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                nodes.push_back(t);\n                nxt.push_back((int)nodes.size() - 1);\n            }\n\n            for (int r = 0; r < 2; r++) {\n                double a = (r ? a1[i] : a0[i]);\n                double b = (r ? b1[i] : b0[i]);\n\n                if (s.curA == 0.0 && s.curB == 0.0 && s.maxDoneA == 0.0 && s.sumDoneB == 0.0) {\n                    Node t;\n                    t.parent = id;\n                    t.act = 1;\n                    t.rot = (unsigned char)r;\n                    t.maxDoneA = 0.0;\n                    t.sumDoneB = 0.0;\n                    t.curA = a;\n                    t.curB = b;\n                    t.pen = s.pen;\n                    t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                    nodes.push_back(t);\n                    nxt.push_back((int)nodes.size() - 1);\n                } else {\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 1;\n                        t.rot = (unsigned char)r;\n                        t.curA = s.curA + a;\n                        t.curB = max(s.curB, b);\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 2;\n                        t.rot = (unsigned char)r;\n                        t.maxDoneA = max(s.maxDoneA, s.curA);\n                        t.sumDoneB = s.sumDoneB + s.curB;\n                        t.curA = a;\n                        t.curB = b;\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                }\n            }\n        }\n\n        if ((int)nxt.size() > beamWidth) {\n            nth_element(nxt.begin(), nxt.begin() + beamWidth, nxt.end(), cmp);\n            nxt.resize(beamWidth);\n        }\n        sort(nxt.begin(), nxt.end(), cmp);\n        beam.swap(nxt);\n    }\n\n    int bestId = beam[0];\n    double bestExact = node_exact_score(nodes[bestId]);\n    for (int id : beam) {\n        double sc = node_exact_score(nodes[id]);\n        if (sc < bestExact) {\n            bestExact = sc;\n            bestId = id;\n        }\n    }\n\n    vector<int> act(N, 0), rot(N, 0);\n    int cur = bestId;\n    for (int i = N - 1; i >= 0; i--) {\n        act[i] = nodes[cur].act;\n        rot[i] = nodes[cur].rot;\n        cur = nodes[cur].parent;\n    }\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool started = false;\n    for (int i = 0; i < N; i++) {\n        if (act[i] == 0) continue;\n        s.used[i] = 1;\n        s.rot[i] = rot[i];\n        if (!started || act[i] == 2) {\n            s.brk[i] = 1;\n            started = true;\n        }\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    Candidate cand = shelf_to_candidate(base, s);\n    return cand;\n}\n\nstatic ShelfSol random_seed_shelf(const vector<Dim>& base, char dir, double targetA, mt19937_64& rng) {\n    int N = (int)base.size();\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    double curA = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (ur(rng) < 0.03) continue;\n\n        double a0, b0, a1, b1;\n        get_ab(base[i], dir, 0, a0, b0);\n        get_ab(base[i], dir, 1, a1, b1);\n\n        double fit0 = fabs((active ? curA : 0.0) + a0 - targetA) + 0.30 * b0;\n        double fit1 = fabs((active ? curA : 0.0) + a1 - targetA) + 0.30 * b1;\n        int r = (fit1 < fit0 ? 1 : 0);\n\n        double a = (r ? a1 : a0);\n        bool newg = !active || curA + a > targetA * (0.85 + 0.40 * ur(rng));\n\n        s.used[i] = 1;\n        s.rot[i] = r;\n        if (newg) {\n            s.brk[i] = 1;\n            curA = a;\n            active = true;\n        } else {\n            curA += a;\n        }\n    }\n\n    if (!active) {\n        int i = (int)(rng() % N);\n        s.used[i] = 1;\n        s.rot[i] = rng() & 1;\n        s.brk[i] = 1;\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    return s;\n}\n\nstatic void mutate_once(ShelfSol& s, mt19937_64& rng) {\n    int N = (int)s.used.size();\n    int typ = (int)(rng() % 100);\n    int i = (int)(rng() % N);\n\n    if (typ < 40) {\n        if (s.used[i]) {\n            s.rot[i] ^= 1;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else if (typ < 75) {\n        if (s.used[i]) {\n            s.used[i] = 0;\n            s.brk[i] = 0;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else {\n        if (s.used[i]) s.brk[i] ^= 1;\n    }\n}\n\nstatic ShelfSol greedy_polish(const vector<Dim>& base, ShelfSol s) {\n    int N = (int)base.size();\n    normalize_shelf(s);\n    double cur = shelf_score_fast(base, s);\n\n    for (int round = 0; round < 3; round++) {\n        bool improved = false;\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.rot[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_fast(base, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.brk[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_fast(base, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (s.used[i]) {\n                ShelfSol t = s;\n                t.used[i] = 0;\n                t.brk[i] = 0;\n                normalize_shelf(t);\n                double sc = shelf_score_fast(base, t);\n                if (sc + 1e-9 < cur) {\n                    s = move(t);\n                    cur = sc;\n                    improved = true;\n                }\n            } else {\n                double bestSc = cur;\n                ShelfSol bestT = s;\n                for (int r = 0; r < 2; r++) {\n                    for (int b = 0; b < 2; b++) {\n                        ShelfSol t = s;\n                        t.used[i] = 1;\n                        t.rot[i] = (unsigned char)r;\n                        t.brk[i] = (unsigned char)b;\n                        normalize_shelf(t);\n                        double sc = shelf_score_fast(base, t);\n                        if (sc + 1e-9 < bestSc) {\n                            bestSc = sc;\n                            bestT = move(t);\n                        }\n                    }\n                }\n                if (bestSc + 1e-9 < cur) {\n                    s = move(bestT);\n                    cur = bestSc;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    s.score = cur;\n    return s;\n}\n\nstatic ShelfSol local_search(\n    const vector<Dim>& base,\n    ShelfSol seed,\n    mt19937_64& rng,\n    int iterations,\n    chrono::steady_clock::time_point deadline\n) {\n    normalize_shelf(seed);\n    seed.score = shelf_score_fast(base, seed);\n\n    ShelfSol cur = seed, best = seed;\n    double curSc = seed.score, bestSc = seed.score;\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 255) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n\n        ShelfSol nxt = cur;\n        int moves = ((rng() % 5) == 0 ? 2 : 1);\n        for (int k = 0; k < moves; k++) mutate_once(nxt, rng);\n        normalize_shelf(nxt);\n        double sc = shelf_score_fast(base, nxt);\n\n        double prog = (double)it / max(1, iterations - 1);\n        double temp = 25000.0 * pow(0.002, prog) + 1.0;\n\n        if (sc < curSc || ur(rng) < exp((curSc - sc) / temp)) {\n            cur = move(nxt);\n            curSc = sc;\n            if (curSc < bestSc) {\n                best = cur;\n                bestSc = curSc;\n            }\n        }\n    }\n\n    best.score = bestSc;\n    best = greedy_polish(base, best);\n    return best;\n}\n\nstatic double robust_eval_candidate(\n    const Candidate& cand,\n    const vector<vector<Dim>>& worlds\n) {\n    double sum = 0.0, mx = -1e100;\n    for (const auto& w : worlds) {\n        double sc = exact_score(w, cand.ops);\n        sum += sc;\n        mx = max(mx, sc);\n    }\n    double mean = sum / worlds.size();\n    return mean + 0.08 * (mx - mean);\n}\n\nstatic vector<Candidate> generate_candidates(\n    const vector<Dim>& base,\n    int remainingTurns,\n    double sigma,\n    double tauW,\n    double tauH,\n    mt19937_64& rng,\n    chrono::steady_clock::time_point deadline\n) {\n    int N = (int)base.size();\n    double area0 = total_area(base);\n    double rootArea = sqrt(max(1.0, area0));\n\n    int beamDet = (N <= 60 ? 520 : 380);\n    int beamRnd = (N <= 60 ? 220 : 160);\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    auto add_cand = [&](Candidate cand) {\n        if (seen.insert(cand.hash).second) {\n            pool.push_back(move(cand));\n        }\n    };\n\n    vector<double> scales = {0.50, 0.63, 0.78, 0.92, 1.05, 1.20, 1.38, 1.60, 1.88};\n    vector<double> omits = {1.00, 1.12, 1.25, 1.40};\n\n    for (double sc : scales) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        add_cand(beam_shelf(base, base, 'L', rootArea * sc, beamDet, 1.15));\n        add_cand(beam_shelf(base, base, 'U', rootArea * sc, beamDet, 1.15));\n    }\n    for (double om : omits) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        add_cand(beam_shelf(base, base, 'L', rootArea, beamDet, om));\n        add_cand(beam_shelf(base, base, 'U', rootArea, beamDet, om));\n    }\n\n    uniform_real_distribution<double> ul(log(0.45), log(2.20));\n    vector<double> alphas = {0.45, 0.80, 1.20};\n\n    int randomBeamAttempts = min(120, remainingTurns + 50);\n    for (int it = 0; it < randomBeamAttempts; it++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        double alpha = alphas[(size_t)(rng() % alphas.size())];\n        auto sample = sample_posterior(base, sigma, alpha, tauW, tauH, rng);\n        double tgt = sqrt(max(1.0, total_area(sample))) * exp(ul(rng));\n        char dir = ((rng() & 1) ? 'L' : 'U');\n        double om = omits[(size_t)(rng() % omits.size())];\n        add_cand(beam_shelf(sample, base, dir, tgt, beamRnd, om));\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.baseScore < b.baseScore;\n    });\n\n    // Local search on top beam seeds.\n    vector<Candidate> enhanced = pool;\n    int topSeeds = min((int)pool.size(), 16);\n    for (int i = 0; i < topSeeds; i++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        ShelfSol s = candidate_to_shelf(pool[i], N);\n        int iters = (i < 8 ? 7000 : 3500);\n        ShelfSol best = local_search(base, s, rng, iters, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    // Random seeds + local search.\n    for (int t = 0; t < 10; t++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        char dir = (t & 1) ? 'L' : 'U';\n        double sc = exp(ul(rng));\n        ShelfSol s = random_seed_shelf(base, dir, rootArea * sc, rng);\n        ShelfSol best = local_search(base, s, rng, 2500, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    // Robust ranking worlds.\n    vector<vector<Dim>> worlds;\n    worlds.push_back(base);\n    worlds.push_back(sample_posterior(base, sigma, 0.60, tauW, tauH, rng));\n    worlds.push_back(sample_posterior(base, sigma, 1.00, tauW, tauH, rng));\n    worlds.push_back(sample_posterior(base, sigma, 1.40, tauW, tauH, rng));\n\n    for (auto& c : enhanced) {\n        c.robustScore = robust_eval_candidate(c, worlds);\n    }\n\n    sort(enhanced.begin(), enhanced.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.robustScore != b.robustScore) return a.robustScore < b.robustScore;\n        return a.baseScore < b.baseScore;\n    });\n\n    // Keep a manageable pool.\n    if ((int)enhanced.size() > 260) enhanced.resize(260);\n    return enhanced;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    int N, T, sigma_i;\n    cin >> N >> T >> sigma_i;\n    double sigma = sigma_i;\n\n    vector<Dim> obs(N);\n    for (int i = 0; i < N; i++) {\n        cin >> obs[i].w >> obs[i].h;\n    }\n\n    mt19937_64 rng(0x3141592653589793ULL);\n\n    vector<double> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) {\n        obsW[i] = obs[i].w;\n        obsH[i] = obs[i].h;\n    }\n\n    int usedTurns = 0;\n\n    // Calibration plan:\n    // always: total width, total height\n    // if T large enough: focused subset width/height\n    // if T even larger: repeated totals via rotated full-line queries\n    bool useSubset = (T >= 20);\n    bool useRepeatTotals = (T >= 32);\n\n    int K = min(max(6, N / 4), 20);\n    vector<int> subsetW = top_k_indices(obsW, K);\n    vector<int> subsetH = top_k_indices(obsH, K);\n\n    vector<double> totalWidthMeasures, totalHeightMeasures;\n    double subsetWidthMeasure = -1.0, subsetHeightMeasure = -1.0;\n\n    // 1) total width by all-in-row, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 0));\n        (void)Hm;\n        totalWidthMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 2) total height by all-in-column, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 0));\n        (void)Wm;\n        totalHeightMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    // 3) focused width subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetW, 'L', 0));\n        (void)Hm;\n        subsetWidthMeasure = (double)Wm;\n        usedTurns++;\n    }\n\n    // 4) focused height subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetH, 'U', 0));\n        (void)Wm;\n        subsetHeightMeasure = (double)Hm;\n        usedTurns++;\n    }\n\n    // 5) repeat total height via all-in-row, rotated (W = sum h)\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 1));\n        (void)Hm;\n        totalHeightMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 6) repeat total width via all-in-column, rotated (H = sum w)\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 1));\n        (void)Wm;\n        totalWidthMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    int remainingTurns = T - usedTurns;\n\n    auto avg = [](const vector<double>& v) {\n        double s = 0.0;\n        for (double x : v) s += x;\n        return s / v.size();\n    };\n\n    double totalW = avg(totalWidthMeasures);\n    double totalH = avg(totalHeightMeasures);\n    double tauW = 1.0 / (double)totalWidthMeasures.size();\n    double tauH = 1.0 / (double)totalHeightMeasures.size();\n\n    vector<double> corrW = correct_groupwise(\n        obsW, totalW, tauW,\n        (subsetWidthMeasure >= 0 ? &subsetW : nullptr),\n        subsetWidthMeasure, 1.0\n    );\n    vector<double> corrH = correct_groupwise(\n        obsH, totalH, tauH,\n        (subsetHeightMeasure >= 0 ? &subsetH : nullptr),\n        subsetHeightMeasure, 1.0\n    );\n\n    vector<Dim> base(N);\n    for (int i = 0; i < N; i++) {\n        base[i].w = corrW[i];\n        base[i].h = corrH[i];\n    }\n\n    if (remainingTurns <= 0) return 0;\n\n    auto deadline = startTime + chrono::milliseconds(2350);\n    auto pool = generate_candidates(base, remainingTurns, sigma, tauW, tauH, rng, deadline);\n    if (pool.empty()) {\n        Candidate fallback = beam_shelf(base, base, 'L', sqrt(max(1.0, total_area(base))), 200, 1.15);\n        pool.push_back(fallback);\n    }\n\n    vector<int> order;\n    int P = (int)pool.size();\n    vector<char> picked(P, 0);\n\n    int topTake = min(P, max(6, remainingTurns * 2 / 3));\n    for (int i = 0; i < topTake; i++) {\n        picked[i] = 1;\n        order.push_back(i);\n    }\n\n    int rem = remainingTurns - (int)order.size();\n    int cap = min(P, max(remainingTurns, min(P, remainingTurns * 3)));\n    if (rem > 0 && cap > topTake) {\n        for (int s = 0; s < rem; s++) {\n            int idx = topTake + (int)((long long)(2 * s + 1) * (cap - topTake) / (2LL * rem));\n            idx = min(idx, cap - 1);\n            if (!picked[idx]) {\n                picked[idx] = 1;\n                order.push_back(idx);\n            }\n        }\n    }\n\n    for (int i = topTake; i < P && (int)order.size() < remainingTurns; i++) {\n        if (!picked[i]) {\n            picked[i] = 1;\n            order.push_back(i);\n        }\n    }\n    while ((int)order.size() < remainingTurns) {\n        order.push_back(0);\n    }\n\n    for (int turn = 0; turn < remainingTurns; turn++) {\n        auto [Wm, Hm] = query_ops(pool[order[turn]].ops);\n        (void)Wm;\n        (void)Hm;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> deg;\n    vector<int> X, Y;\n\n    mt19937_64 rng{chrono::steady_clock::now().time_since_epoch().count()};\n    chrono::steady_clock::time_point start_time, deadline;\n\n    struct State {\n        vector<vector<int>> children;\n        vector<vector<int>> comps;\n        vector<int> roots;\n        vector<int> depth, tin, tout, compId;\n        vector<int> subtreeBeauty;\n        vector<int> maxAbsDepth;\n        long long score = 0;\n    };\n\n    struct Move {\n        long long gain = 0;\n        int par = -1;\n        int child = -1;\n        int parentSub = 0;\n        int parDepth = 0;\n        int parentDeg = 0;\n        int parentA = 0;\n        int childSub = 0;\n    };\n\n    bool time_up() const {\n        return chrono::steady_clock::now() >= deadline;\n    }\n\n    long long remaining_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(deadline - chrono::steady_clock::now()).count();\n    }\n\n    static bool betterMove(const Move& a, const Move& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.parDepth != b.parDepth) return a.parDepth > b.parDepth;\n        if (a.parentA != b.parentA) return a.parentA < b.parentA;\n        if (a.parentSub != b.parentSub) return a.parentSub < b.parentSub;\n        if (a.parentDeg != b.parentDeg) return a.parentDeg > b.parentDeg;\n        if (a.childSub != b.childSub) return a.childSub > b.childSub;\n        if (a.child != b.child) return a.child < b.child;\n        return a.par < b.par;\n    }\n\n    void rebuild(const vector<int>& parent, State& st) {\n        st.children.assign(N, {});\n        st.roots.clear();\n        st.depth.assign(N, 0);\n        st.tin.assign(N, 0);\n        st.tout.assign(N, 0);\n        st.compId.assign(N, -1);\n        st.subtreeBeauty.assign(N, 0);\n        st.maxAbsDepth.assign(N, 0);\n        st.comps.clear();\n        st.score = 1;\n\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] == -1) st.roots.push_back(v);\n            else st.children[parent[v]].push_back(v);\n        }\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v, int comp) -> void {\n            st.compId[v] = comp;\n            st.tin[v] = timer++;\n            st.comps[comp].push_back(v);\n\n            st.subtreeBeauty[v] = A[v];\n            st.maxAbsDepth[v] = st.depth[v];\n            st.score += 1LL * (st.depth[v] + 1) * A[v];\n\n            for (int ch : st.children[v]) {\n                st.depth[ch] = st.depth[v] + 1;\n                self(self, ch, comp);\n                st.subtreeBeauty[v] += st.subtreeBeauty[ch];\n                st.maxAbsDepth[v] = max(st.maxAbsDepth[v], st.maxAbsDepth[ch]);\n            }\n            st.tout[v] = timer;\n        };\n\n        for (int r : st.roots) {\n            st.depth[r] = 0;\n            st.comps.push_back({});\n            dfs(dfs, r, (int)st.comps.size() - 1);\n        }\n    }\n\n    bool makeCandidate(int par, int child, const State& st, Move& mv) {\n        int newDepth = st.depth[par] + 1;\n        if (newDepth > H) return false;\n        if (newDepth <= st.depth[child]) return false;\n\n        if (st.compId[par] == st.compId[child]) {\n            if (st.tin[child] <= st.tin[par] && st.tin[par] < st.tout[child]) {\n                return false;\n            }\n        }\n\n        int delta = newDepth - st.depth[child];\n        if (st.maxAbsDepth[child] + delta > H) return false;\n\n        mv.gain = 1LL * delta * st.subtreeBeauty[child];\n        if (mv.gain <= 0) return false;\n\n        mv.par = par;\n        mv.child = child;\n        mv.parentSub = st.subtreeBeauty[par];\n        mv.parDepth = st.depth[par];\n        mv.parentDeg = deg[par];\n        mv.parentA = A[par];\n        mv.childSub = st.subtreeBeauty[child];\n        return true;\n    }\n\n    bool findMoveDeterministic(const State& st, Move& best) {\n        bool found = false;\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool findMoveRandomized(const State& st, Move& chosen) {\n        vector<Move> cand;\n        cand.reserve(2 * M);\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) cand.push_back(mv);\n            if (makeCandidate(v, u, st, mv)) cand.push_back(mv);\n        }\n        if (cand.empty()) return false;\n\n        sort(cand.begin(), cand.end(), betterMove);\n        long long bestGain = cand[0].gain;\n\n        vector<int> idx;\n        idx.reserve(32);\n        for (int i = 0; i < (int)cand.size() && (int)idx.size() < 32; ++i) {\n            if (cand[i].gain * 100 >= bestGain * 95) idx.push_back(i);\n            else break;\n        }\n        if (idx.empty()) idx.push_back(0);\n\n        uniform_int_distribution<int> dist(0, (int)idx.size() - 1);\n        chosen = cand[idx[dist(rng)]];\n        return true;\n    }\n\n    void hillClimb(vector<int>& parent, bool randomized) {\n        while (!time_up()) {\n            State st;\n            rebuild(parent, st);\n\n            Move mv;\n            bool ok = randomized ? findMoveRandomized(st, mv)\n                                 : findMoveDeterministic(st, mv);\n            if (!ok) break;\n\n            parent[mv.child] = mv.par;\n        }\n    }\n\n    bool rerootOptimize(vector<int>& parent) {\n        if (time_up()) return false;\n\n        State st;\n        rebuild(parent, st);\n\n        vector<vector<int>> treeAdj(N);\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] != -1) {\n                treeAdj[v].push_back(parent[v]);\n                treeAdj[parent[v]].push_back(v);\n            }\n        }\n\n        vector<int> newParent = parent;\n        bool changedAny = false;\n\n        auto dfsScore = [&](auto&& self, int v, int p, int d, long long& sc, int& mx,\n                            const vector<vector<int>>& adj) -> void {\n            sc += 1LL * A[v] * d;\n            mx = max(mx, d);\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, d + 1, sc, mx, adj);\n            }\n        };\n\n        auto dfsOrient = [&](auto&& self, int v, int p,\n                             vector<int>& par, const vector<vector<int>>& adj) -> void {\n            par[v] = p;\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, par, adj);\n            }\n        };\n\n        for (const auto& comp : st.comps) {\n            if (time_up()) return changedAny;\n            if (comp.size() <= 1) continue;\n\n            long long bestScore = LLONG_MIN;\n            int bestRoot = comp[0];\n\n            for (int r : comp) {\n                long long sc = 0;\n                int mx = 0;\n                dfsScore(dfsScore, r, -1, 0, sc, mx, treeAdj);\n                if (mx > H) continue;\n\n                bool better = false;\n                if (sc > bestScore) better = true;\n                else if (sc == bestScore) {\n                    if (A[r] < A[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] > deg[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] == deg[bestRoot] && r < bestRoot) better = true;\n                }\n                if (better) {\n                    bestScore = sc;\n                    bestRoot = r;\n                }\n            }\n\n            if (bestScore == LLONG_MIN) continue;\n            dfsOrient(dfsOrient, bestRoot, -1, newParent, treeAdj);\n        }\n\n        if (newParent != parent) {\n            parent.swap(newParent);\n            changedAny = true;\n        }\n        return changedAny;\n    }\n\n    long long calcScore(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.score;\n    }\n\n    vector<int> buildAllRoots() {\n        return vector<int>(N, -1);\n    }\n\n    vector<int> buildFromKey(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n\n        vector<int> parent(N, -1), depth(N, 0);\n        vector<char> done(N, 0);\n\n        auto betterPar = [&](int x, int y, const vector<int>& depthRef) {\n            if (y == -1) return true;\n            if (depthRef[x] != depthRef[y]) return depthRef[x] > depthRef[y];\n            if (A[x] != A[y]) return A[x] < A[y];\n            if (deg[x] != deg[y]) return deg[x] > deg[y];\n            return x < y;\n        };\n\n        for (int v : ord) {\n            int bestPar = -1;\n            for (int to : g[v]) {\n                if (!done[to]) continue;\n                if (depth[to] >= H) continue;\n                if (betterPar(to, bestPar, depth)) bestPar = to;\n            }\n            if (bestPar != -1) {\n                parent[v] = bestPar;\n                depth[v] = depth[bestPar] + 1;\n            } else {\n                parent[v] = -1;\n                depth[v] = 0;\n            }\n            done[v] = 1;\n        }\n        return parent;\n    }\n\n    vector<int> bfsDist(int s) {\n        const int INF = 1e9;\n        vector<int> dist(N, INF);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (int to : g[v]) {\n                if (dist[to] != INF) continue;\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n        return dist;\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    vector<int> buildBeautyOrder(double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = 1.0 * A[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildBeautyDegreeOrder(double wA, double wDeg, double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = wA * A[v] - wDeg * deg[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildProjectionOrder(double angle, double wA, double wP, double noiseScale = 1e-4) {\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildSeedDistOrder(int seed, double wD, double wA, double angle = 0.0,\n                                   double wP = 0.0, double noiseScale = 1e-4) {\n        auto dist = bfsDist(seed);\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wD * dist[v] + wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> seedCandidates() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            long long da = 1LL * (X[a] - 500) * (X[a] - 500) + 1LL * (Y[a] - 500) * (Y[a] - 500);\n            long long db = 1LL * (X[b] - 500) * (X[b] - 500) + 1LL * (Y[b] - 500) * (Y[b] - 500);\n            double sa = 18.0 * A[a] - 2.5 * deg[a] + 0.002 * sqrt((double)da);\n            double sb = 18.0 * A[b] - 2.5 * deg[b] + 0.002 * sqrt((double)db);\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n        int K = min(20, N);\n        ord.resize(K);\n        return ord;\n    }\n\n    void polish(vector<int>& parent, bool randomizedFirst) {\n        if (time_up()) return;\n\n        // Light exact improvement first.\n        rerootOptimize(parent);\n        if (time_up()) return;\n\n        // Randomized hill climb.\n        hillClimb(parent, randomizedFirst);\n        if (time_up()) return;\n\n        // Alternate reroot / deterministic climb.\n        for (int phase = 0; phase < 2 && !time_up(); ++phase) {\n            bool changed = rerootOptimize(parent);\n            if (time_up()) return;\n            hillClimb(parent, false);\n            if (!changed) break;\n        }\n    }\n\n    void tryUpdate(const vector<int>& cand, vector<int>& bestParent, long long& bestScore) {\n        long long sc = calcScore(cand);\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestParent = cand;\n        }\n    }\n\n    vector<int> solve() {\n        start_time = chrono::steady_clock::now();\n        deadline = start_time + chrono::milliseconds(1900);\n\n        vector<int> bestParent = buildAllRoots();\n        long long bestScore = calcScore(bestParent);\n\n        auto seeds = seedCandidates();\n\n        auto runCandidate = [&](vector<int> p, bool randomizedFirst) {\n            if (time_up()) return;\n            polish(p, randomizedFirst);\n            tryUpdate(p, bestParent, bestScore);\n        };\n\n        // Baseline.\n        runCandidate(buildAllRoots(), false);\n\n        // Deterministic initializations.\n        runCandidate(buildBeautyOrder(), true);\n        runCandidate(buildBeautyDegreeOrder(1.0, 1.5), true);\n        runCandidate(buildBeautyDegreeOrder(1.5, 2.0), true);\n\n        const vector<double> fixedAngles = {\n            0.0,\n            acos(-1.0) / 4.0,\n            acos(-1.0) / 2.0,\n            3.0 * acos(-1.0) / 4.0\n        };\n        for (double ang : fixedAngles) {\n            if (time_up()) break;\n            runCandidate(buildProjectionOrder(ang, 1.3, 0.05), true);\n            if (time_up()) break;\n            runCandidate(buildProjectionOrder(ang, 1.8, 0.035), true);\n        }\n\n        for (int i = 0; i < (int)seeds.size() && i < 6 && !time_up(); ++i) {\n            int s = seeds[i];\n            double ang = 2.0 * acos(-1.0) * (i + 1) / 7.0;\n            runCandidate(buildSeedDistOrder(s, 10.0, 1.0, ang, 0.015), true);\n            if (time_up()) break;\n            runCandidate(buildSeedDistOrder(s, 14.0, 0.8, ang, 0.0), true);\n        }\n\n        // Randomized multi-start.\n        int trial = 0;\n        while (!time_up()) {\n            vector<int> p;\n            int typ = trial % 4;\n\n            if (typ == 0) {\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wA = 0.8 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.08;\n                p = buildProjectionOrder(ang, wA, wP);\n            } else if (typ == 1) {\n                int s = seeds[uniform_int_distribution<int>(0, (int)seeds.size() - 1)(rng)];\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wD = 7.0 + 10.0 * rand01();\n                double wA = 0.6 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.03;\n                p = buildSeedDistOrder(s, wD, wA, ang, wP);\n            } else if (typ == 2) {\n                double wA = 0.8 + 1.2 * rand01();\n                double wDeg = 0.5 + 2.5 * rand01();\n                p = buildBeautyDegreeOrder(wA, wDeg);\n            } else {\n                p = buildBeautyOrder(1e-3);\n            }\n\n            bool randomizedFirst = (remaining_ms() > 250);\n            runCandidate(p, randomizedFirst);\n            ++trial;\n        }\n\n        // Final deterministic polish from the best found.\n        if (!time_up()) {\n            vector<int> finalP = bestParent;\n            polish(finalP, false);\n            tryUpdate(finalP, bestParent, bestScore);\n        }\n\n        return bestParent;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M >> solver.H;\n    solver.A.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.A[i];\n\n    solver.edges.resize(solver.M);\n    solver.g.assign(solver.N, {});\n    solver.deg.assign(solver.N, 0);\n\n    for (int i = 0; i < solver.M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        solver.edges[i] = {u, v};\n        solver.g[u].push_back(v);\n        solver.g[v].push_back(u);\n        solver.deg[u]++;\n        solver.deg[v]++;\n    }\n\n    solver.X.resize(solver.N);\n    solver.Y.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) {\n        cin >> solver.X[i] >> solver.Y[i];\n    }\n\n    vector<int> ans = solver.solve();\n\n    for (int i = 0; i < solver.N; ++i) {\n        if (i) cout << ' ';\n        cout << ans[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAX_ONI = 40;\nstatic constexpr int SIDE = 80;\nstatic constexpr int MAXD = 20;\nstatic constexpr double TL = 1.92;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n} timer_;\n\nmt19937_64 rng_(chrono::steady_clock::now().time_since_epoch().count());\n\ninline int sideL(int r) { return r; }\ninline int sideR(int r) { return 20 + r; }\ninline int sideU(int c) { return 40 + c; }\ninline int sideD(int c) { return 60 + c; }\n\ninline char sideDir(int s) {\n    if (s < 20) return 'L';\n    if (s < 40) return 'R';\n    if (s < 60) return 'U';\n    return 'D';\n}\ninline int sideIdx(int s) {\n    if (s < 20) return s;\n    if (s < 40) return s - 20;\n    if (s < 60) return s - 40;\n    return s - 60;\n}\ninline char revDir(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\nstruct Macro {\n    char d;\n    int p;\n    int k;\n};\n\nstruct Board {\n    array<array<char, N>, N> g{};\n    int xcnt = 0;\n};\n\nstruct FinishData {\n    int m = 0;\n    bool safe = true;\n    array<pair<int,int>, MAX_ONI> pos{};\n    array<array<int, 4>, MAX_ONI> candList{};\n    array<int, MAX_ONI> candCnt{};\n    array<array<int, SIDE>, MAX_ONI> depthOf{};\n    array<int, MAX_ONI> minDepth{};\n    array<int, N> firstORow{}, lastORow{}, firstOCol{}, lastOCol{};\n};\n\nstruct State {\n    array<int, MAX_ONI> assign{};\n    array<array<unsigned char, MAXD + 1>, SIDE> cnt{};\n    array<int, SIDE> dep{};\n    array<unsigned long long, SIDE> mem{};\n    int S = 0;\n    int M = 0;\n    int cost() const { return S - M; }\n};\n\nstruct Endpoint {\n    Board b;\n    vector<Macro> prefix;\n    int prefixCost = 0;\n    int quickTotal = (int)1e9;\n    uint64_t h = 0;\n};\n\nuint64_t hashBoard(const Board& b) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            h ^= (uint64_t)(unsigned char)b.g[i][j];\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nvoid applyOne(Board& b, char d, int p) {\n    if (d == 'L') {\n        if (b.g[p][0] == 'x') b.xcnt--;\n        for (int j = 0; j + 1 < N; j++) b.g[p][j] = b.g[p][j + 1];\n        b.g[p][N - 1] = '.';\n    } else if (d == 'R') {\n        if (b.g[p][N - 1] == 'x') b.xcnt--;\n        for (int j = N - 1; j >= 1; j--) b.g[p][j] = b.g[p][j - 1];\n        b.g[p][0] = '.';\n    } else if (d == 'U') {\n        if (b.g[0][p] == 'x') b.xcnt--;\n        for (int i = 0; i + 1 < N; i++) b.g[i][p] = b.g[i + 1][p];\n        b.g[N - 1][p] = '.';\n    } else {\n        if (b.g[N - 1][p] == 'x') b.xcnt--;\n        for (int i = N - 1; i >= 1; i--) b.g[i][p] = b.g[i - 1][p];\n        b.g[0][p] = '.';\n    }\n}\n\nvoid applyMacro(Board& b, const Macro& a) {\n    for (int t = 0; t < a.k; t++) applyOne(b, a.d, a.p);\n}\n\nFinishData buildData(const Board& b) {\n    FinishData D;\n    for (int i = 0; i < N; i++) {\n        D.firstORow[i] = N;\n        D.lastORow[i] = -1;\n    }\n    for (int j = 0; j < N; j++) {\n        D.firstOCol[j] = N;\n        D.lastOCol[j] = -1;\n    }\n\n    D.m = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] == 'o') {\n                D.firstORow[i] = min(D.firstORow[i], j);\n                D.lastORow[i] = max(D.lastORow[i], j);\n                D.firstOCol[j] = min(D.firstOCol[j], i);\n                D.lastOCol[j] = max(D.lastOCol[j], i);\n            }\n        }\n    }\n\n    for (int u = 0; u < MAX_ONI; u++) {\n        D.candCnt[u] = 0;\n        D.minDepth[u] = 1e9;\n        D.depthOf[u].fill(0);\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] != 'x') continue;\n            int u = D.m++;\n            D.pos[u] = {i, j};\n\n            auto addCand = [&](int s, int d) {\n                int c = D.candCnt[u];\n                D.candList[u][c] = s;\n                D.candCnt[u]++;\n                D.depthOf[u][s] = d;\n                D.minDepth[u] = min(D.minDepth[u], d);\n            };\n\n            if (j < D.firstORow[i]) addCand(sideL(i), j + 1);\n            if (j > D.lastORow[i]) addCand(sideR(i), N - j);\n            if (i < D.firstOCol[j]) addCand(sideU(j), i + 1);\n            if (i > D.lastOCol[j]) addCand(sideD(j), N - i);\n\n            if (D.candCnt[u] == 0) D.safe = false;\n        }\n    }\n    return D;\n}\n\nvector<Macro> enumerateMacros(const Board& b, const FinishData& D) {\n    vector<Macro> acts;\n    acts.reserve(4 * max(1, D.m));\n\n    for (int r = 0; r < N; r++) {\n        int limL = D.firstORow[r];\n        for (int j = 0; j < limL; j++) {\n            if (b.g[r][j] == 'x') acts.push_back({'L', r, j + 1});\n        }\n        int limR = (D.lastORow[r] == -1 ? N : N - 1 - D.lastORow[r]);\n        for (int j = N - 1; j >= N - limR; j--) {\n            if (b.g[r][j] == 'x') acts.push_back({'R', r, N - j});\n        }\n    }\n    for (int c = 0; c < N; c++) {\n        int limU = D.firstOCol[c];\n        for (int i = 0; i < limU; i++) {\n            if (b.g[i][c] == 'x') acts.push_back({'U', c, i + 1});\n        }\n        int limD = (D.lastOCol[c] == -1 ? N : N - 1 - D.lastOCol[c]);\n        for (int i = N - 1; i >= N - limD; i--) {\n            if (b.g[i][c] == 'x') acts.push_back({'D', c, N - i});\n        }\n    }\n\n    return acts;\n}\n\nState emptyState() {\n    State st;\n    st.assign.fill(-1);\n    for (int s = 0; s < SIDE; s++) {\n        st.cnt[s].fill(0);\n        st.dep[s] = 0;\n        st.mem[s] = 0ULL;\n    }\n    st.S = 0;\n    st.M = 0;\n    return st;\n}\n\ninline int recomputeM(const State& st) {\n    int m = 0;\n    for (int s = 0; s < SIDE; s++) m = max(m, st.dep[s]);\n    return m;\n}\n\nvoid addAssign(State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    st.assign[u] = s;\n    st.mem[s] |= (1ULL << u);\n    st.cnt[s][d]++;\n    if (d > st.dep[s]) {\n        st.S += 2 * (d - st.dep[s]);\n        st.dep[s] = d;\n    }\n    if (st.dep[s] > st.M) st.M = st.dep[s];\n}\n\nvoid removeAssign(State& st, const FinishData& D, int u) {\n    int s = st.assign[u];\n    if (s < 0) return;\n    int d = D.depthOf[u][s];\n    st.assign[u] = -1;\n    st.mem[s] &= ~(1ULL << u);\n    st.cnt[s][d]--;\n    if (d == st.dep[s] && st.cnt[s][d] == 0) {\n        int nd = st.dep[s];\n        while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n        st.S += 2 * (nd - st.dep[s]);\n        st.dep[s] = nd;\n    }\n    st.M = recomputeM(st);\n}\n\ninline int secondDepthAfterRemoving(const State& st, int s, int remDepth) {\n    if (remDepth != st.dep[s]) return st.dep[s];\n    if (st.cnt[s][remDepth] >= 2) return st.dep[s];\n    int nd = st.dep[s] - 1;\n    while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n    return nd;\n}\n\nint evalAdd(const State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    int nd = max(st.dep[s], d);\n    int newS = st.S + 2 * (nd - st.dep[s]);\n    int newM = max(st.M, nd);\n    return newS - newM;\n}\n\nint evalMove(const State& st, const FinishData& D, int u, int ns) {\n    int os = st.assign[u];\n    if (os == ns) return st.cost();\n\n    int od = D.depthOf[u][os];\n    int nd = D.depthOf[u][ns];\n    int depOldAfter = secondDepthAfterRemoving(st, os, od);\n    int depNewAfter = max(st.dep[ns], nd);\n\n    int newS = st.S\n        + 2 * (depOldAfter - st.dep[os])\n        + 2 * (depNewAfter - st.dep[ns]);\n\n    int newM = 0;\n    for (int s = 0; s < SIDE; s++) {\n        int d = st.dep[s];\n        if (s == os) d = depOldAfter;\n        else if (s == ns) d = depNewAfter;\n        newM = max(newM, d);\n    }\n    return newS - newM;\n}\n\nvector<int> makeOrderDifficulty(const FinishData& D, bool randomized) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    vector<uint64_t> key(D.m);\n    for (int i = 0; i < D.m; i++) key[i] = rng_();\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D.candCnt[a] != D.candCnt[b]) return D.candCnt[a] < D.candCnt[b];\n        if (D.minDepth[a] != D.minDepth[b]) return D.minDepth[a] > D.minDepth[b];\n        if (randomized) return key[a] < key[b];\n        return a < b;\n    });\n    return ord;\n}\n\nvector<int> makeOrderRandom(int m) {\n    vector<int> ord(m);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng_);\n    return ord;\n}\n\nState buildGreedy(const FinishData& D, const vector<int>& ord, bool randomized) {\n    State st = emptyState();\n    for (int u : ord) {\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            opts[oc++] = {evalAdd(st, D, u, s), s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        int choose = opts[0].second;\n        if (randomized && oc > 1) {\n            int lim = 1;\n            while (lim < oc && opts[lim].first <= opts[0].first + 1) ++lim;\n            lim = min(lim, 3);\n            choose = opts[(int)(rng_() % lim)].second;\n        }\n        addAssign(st, D, u, choose);\n    }\n    return st;\n}\n\nState buildMinDepthState(const FinishData& D) {\n    State st = emptyState();\n    for (int u = 0; u < D.m; u++) {\n        int bestS = D.candList[u][0];\n        int bestD = D.depthOf[u][bestS];\n        for (int it = 1; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            int d = D.depthOf[u][s];\n            if (d < bestD || (d == bestD && s < bestS)) {\n                bestD = d;\n                bestS = s;\n            }\n        }\n        addAssign(st, D, u, bestS);\n    }\n    return st;\n}\n\nvoid local1(const FinishData& D, State& st, int rounds = 2) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    for (int rep = 0; rep < rounds; rep++) {\n        bool improved = false;\n        for (int u : ord) {\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvector<int> membersOfMask(unsigned long long mask) {\n    vector<int> res;\n    while (mask) {\n        int b = __builtin_ctzll(mask);\n        res.push_back(b);\n        mask &= mask - 1;\n    }\n    return res;\n}\n\nbool exactReoptSubset(State& st, const FinishData& D, vector<int> subset, int forbidSide, double deadline) {\n    if (subset.empty()) return false;\n\n    State original = st;\n    for (int u : subset) removeAssign(st, D, u);\n\n    for (int u : subset) {\n        int ok = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != forbidSide) ok++;\n        }\n        if (ok == 0) {\n            st = original;\n            return false;\n        }\n    }\n\n    sort(subset.begin(), subset.end(), [&](int a, int b) {\n        int ca = 0, cb = 0;\n        for (int it = 0; it < D.candCnt[a]; it++) if (D.candList[a][it] != forbidSide) ca++;\n        for (int it = 0; it < D.candCnt[b]; it++) if (D.candList[b][it] != forbidSide) cb++;\n        if (ca != cb) return ca < cb;\n        return D.minDepth[a] > D.minDepth[b];\n    });\n\n    int bestCost = original.cost();\n    State bestState = original;\n    long long nodes = 0;\n    bool timeout = false;\n\n    function<void(int)> dfs = [&](int idx) {\n        if ((nodes++ & 1023LL) == 0 && timer_.elapsed() >= deadline) {\n            timeout = true;\n            return;\n        }\n        int curCost = st.cost();\n        if (curCost >= bestCost) return;\n        if (idx == (int)subset.size()) {\n            bestCost = curCost;\n            bestState = st;\n            return;\n        }\n\n        int u = subset[idx];\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            if (s == forbidSide) continue;\n            int c = evalAdd(st, D, u, s);\n            if (c < bestCost) opts[oc++] = {c, s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        for (int i = 0; i < oc; i++) {\n            int s = opts[i].second;\n            int c = opts[i].first;\n            if (c >= bestCost) break;\n            addAssign(st, D, u, s);\n            dfs(idx + 1);\n            removeAssign(st, D, u);\n            if (timeout) return;\n        }\n    };\n\n    dfs(0);\n    st = bestState;\n    return st.cost() < original.cost();\n}\n\nbool exactCloseOneSide(State& st, const FinishData& D, int side, double deadline) {\n    int sz = __builtin_popcountll(st.mem[side]);\n    if (sz <= 1 || sz > 8) return false;\n    vector<int> subset = membersOfMask(st.mem[side]);\n    for (int u : subset) {\n        bool alt = false;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != side) { alt = true; break; }\n        }\n        if (!alt) return false;\n    }\n    return exactReoptSubset(st, D, subset, side, deadline);\n}\n\nvoid localImproveStrong(const FinishData& D, State& st, double deadline) {\n    while (timer_.elapsed() < deadline) {\n        bool improved = false;\n\n        vector<int> ord(D.m);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng_);\n\n        for (int u : ord) {\n            if (timer_.elapsed() >= deadline) return;\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        vector<int> sides;\n        for (int s = 0; s < SIDE; s++) {\n            int sz = __builtin_popcountll(st.mem[s]);\n            if (sz >= 2 && sz <= 8) sides.push_back(s);\n        }\n        shuffle(sides.begin(), sides.end(), rng_);\n        for (int s : sides) {\n            if (timer_.elapsed() >= deadline) return;\n            if (exactCloseOneSide(st, D, s, deadline)) {\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nState quickSolve(const FinishData& D) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    State best = buildGreedy(D, makeOrderDifficulty(D, false), false);\n    local1(D, best, 2);\n\n    State alt = buildMinDepthState(D);\n    local1(D, alt, 2);\n    if (alt.cost() < best.cost()) best = alt;\n\n    return best;\n}\n\nState strongSolve(const FinishData& D, double deadline) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    State best = quickSolve(D);\n    localImproveStrong(D, best, deadline);\n\n    int iter = 0;\n    while (timer_.elapsed() < deadline) {\n        State st;\n        if ((iter & 1) == 0) st = buildGreedy(D, makeOrderDifficulty(D, true), true);\n        else st = buildGreedy(D, makeOrderRandom(D.m), true);\n\n        localImproveStrong(D, st, deadline);\n        if (st.cost() < best.cost()) best = st;\n        iter++;\n    }\n    return best;\n}\n\nvoid emitSide(vector<pair<char,int>>& ops, int side, int depth, bool restore) {\n    char d = sideDir(side);\n    char rd = revDir(d);\n    int p = sideIdx(side);\n    for (int t = 0; t < depth; t++) ops.push_back({d, p});\n    if (restore) {\n        for (int t = 0; t < depth; t++) ops.push_back({rd, p});\n    }\n}\n\nvector<pair<char,int>> buildFinishOps(const State& st) {\n    vector<int> used;\n    for (int s = 0; s < SIDE; s++) if (st.dep[s] > 0) used.push_back(s);\n    vector<pair<char,int>> ops;\n    if (used.empty()) return ops;\n\n    int finalSide = used[0];\n    for (int s : used) {\n        if (st.dep[s] > st.dep[finalSide]) finalSide = s;\n    }\n\n    sort(used.begin(), used.end(), [&](int a, int b) {\n        if (st.dep[a] != st.dep[b]) return st.dep[a] < st.dep[b];\n        return a < b;\n    });\n\n    for (int s : used) {\n        if (s == finalSide) continue;\n        emitSide(ops, s, st.dep[s], true);\n    }\n    emitSide(ops, finalSide, st.dep[finalSide], false);\n    return ops;\n}\n\nvector<pair<char,int>> buildPlan(const vector<Macro>& prefix, const State& st) {\n    vector<pair<char,int>> ops;\n    for (auto &m : prefix) {\n        for (int t = 0; t < m.k; t++) ops.push_back({m.d, m.p});\n    }\n    auto fin = buildFinishOps(st);\n    ops.insert(ops.end(), fin.begin(), fin.end());\n    return ops;\n}\n\npair<int,int> simulate(const Board& init, const vector<pair<char,int>>& ops) {\n    Board b = init;\n    int removedO = 0;\n\n    for (auto [d, p] : ops) {\n        if (d == 'L') {\n            if (b.g[p][0] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'R') {\n            if (b.g[p][N - 1] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'U') {\n            if (b.g[0][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else {\n            if (b.g[N - 1][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        }\n    }\n    return {b.xcnt, removedO};\n}\n\nvoid addEndpoint(vector<Endpoint>& eps, const Endpoint& e, int keep = 12) {\n    for (auto& x : eps) {\n        if (x.h == e.h) {\n            if (e.quickTotal < x.quickTotal) x = e;\n            return;\n        }\n    }\n    eps.push_back(e);\n    sort(eps.begin(), eps.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        return a.prefixCost < b.prefixCost;\n    });\n    if ((int)eps.size() > keep) eps.resize(keep);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n_in;\n    cin >> n_in;\n\n    Board init;\n    init.xcnt = 0;\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) {\n            init.g[i][j] = s[j];\n            if (s[j] == 'x') init.xcnt++;\n        }\n    }\n\n    vector<pair<char,int>> bestOps;\n    int bestLen = 1e9;\n\n    // Baseline strong finisher from initial board.\n    FinishData D0 = buildData(init);\n    double baseDeadline = min(TL * 0.18, 0.30);\n    State baseState = strongSolve(D0, timer_.elapsed() + baseDeadline);\n    {\n        auto ops = buildFinishOps(baseState);\n        auto [rx, ry] = simulate(init, ops);\n        if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) {\n            bestOps = ops;\n            bestLen = (int)ops.size();\n        }\n    }\n\n    vector<Endpoint> eps;\n    eps.push_back({init, {}, 0, baseState.cost(), hashBoard(init)});\n\n    // Randomized hill-climbing over one-way macro-actions.\n    double searchEnd = 1.55;\n    int restart = 0;\n\n    while (timer_.elapsed() < searchEnd) {\n        Board curB = init;\n        vector<Macro> prefix;\n        int prefixCost = 0;\n\n        FinishData curD = buildData(curB);\n        if (!curD.safe) break;\n        int curTotal = prefixCost + quickSolve(curD).cost();\n\n        int style = restart % 4;\n        restart++;\n\n        for (int step = 0; step < 12 && timer_.elapsed() < searchEnd; step++) {\n            auto acts = enumerateMacros(curB, curD);\n            if (acts.empty()) break;\n\n            struct Cand {\n                int total;\n                int qcost;\n                int xRemoved;\n                Macro a;\n                Board b;\n                FinishData d;\n            };\n            vector<Cand> cands;\n            cands.reserve(acts.size());\n\n            for (const auto& a : acts) {\n                Board nb = curB;\n                int beforeX = nb.xcnt;\n                applyMacro(nb, a);\n                FinishData nd = buildData(nb);\n                if (!nd.safe) continue;\n                State qst = quickSolve(nd);\n                int total = prefixCost + a.k + qst.cost();\n                if (total <= curTotal) {\n                    cands.push_back({total, qst.cost(), beforeX - nb.xcnt, a, nb, nd});\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand& A, const Cand& B) {\n                if (A.total != B.total) return A.total < B.total;\n                if (A.xRemoved != B.xRemoved) return A.xRemoved > B.xRemoved;\n                return A.a.k < B.a.k;\n            });\n\n            int idx = 0;\n            if (style == 1) {\n                int lim = min<int>(3, cands.size());\n                idx = (int)(rng_() % lim);\n            } else if (style == 2) {\n                int lim = min<int>(5, cands.size());\n                vector<int> w(lim);\n                int sum = 0;\n                for (int i = 0; i < lim; i++) sum += (w[i] = lim - i);\n                int r = (int)(rng_() % sum);\n                int acc = 0;\n                for (int i = 0; i < lim; i++) {\n                    acc += w[i];\n                    if (r < acc) { idx = i; break; }\n                }\n            } else if (style == 3) {\n                int lim = min<int>(4, cands.size());\n                int bestScore = -1;\n                for (int i = 0; i < lim; i++) {\n                    int sc = 100 * cands[i].xRemoved - cands[i].a.k;\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        idx = i;\n                    }\n                }\n            }\n\n            auto chosen = cands[idx];\n            prefix.push_back(chosen.a);\n            prefixCost += chosen.a.k;\n            curB = chosen.b;\n            curD = chosen.d;\n            curTotal = chosen.total;\n\n            if (curB.xcnt == 0) break;\n        }\n\n        Endpoint ep;\n        ep.b = curB;\n        ep.prefix = prefix;\n        ep.prefixCost = prefixCost;\n        ep.quickTotal = curTotal;\n        ep.h = hashBoard(curB);\n\n        if (curTotal < bestLen) addEndpoint(eps, ep, 14);\n    }\n\n    sort(eps.begin(), eps.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        return a.prefixCost < b.prefixCost;\n    });\n\n    // Strong evaluation of promising endpoints.\n    for (int i = 0; i < (int)eps.size(); i++) {\n        if (timer_.elapsed() >= TL - 0.03) break;\n        if (eps[i].quickTotal >= bestLen) continue;\n\n        double remain = TL - 0.02 - timer_.elapsed();\n        int left = (int)eps.size() - i;\n        double budget = min(0.18, max(0.03, remain / max(1, left)));\n\n        FinishData D = buildData(eps[i].b);\n        if (!D.safe) continue;\n        State st = strongSolve(D, timer_.elapsed() + budget);\n        auto ops = buildPlan(eps[i].prefix, st);\n\n        auto [rx, ry] = simulate(init, ops);\n        if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) {\n            if ((int)ops.size() < bestLen) {\n                bestLen = (int)ops.size();\n                bestOps = ops;\n            }\n        }\n    }\n\n    // Final validation fallback.\n    if (bestOps.empty()) {\n        auto ops = buildFinishOps(baseState);\n        auto [rx, ry] = simulate(init, ops);\n        if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) bestOps = ops;\n    } else {\n        auto [rx, ry] = simulate(init, bestOps);\n        if (!((int)bestOps.size() <= 4 * N * N && rx == 0 && ry == 0)) {\n            auto ops = buildFinishOps(baseState);\n            auto [rx2, ry2] = simulate(init, ops);\n            if ((int)ops.size() <= 4 * N * N && rx2 == 0 && ry2 == 0) bestOps = ops;\n        }\n    }\n\n    for (auto [d, p] : bestOps) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct SimResult {\n    vector<int> cnt;\n    int end_node;\n    ll err;\n};\n\nstruct BuildResult {\n    vector<int> a, b;\n    ll approx_cost;\n};\n\nstruct Candidate {\n    vector<int> order, a, b, cnt;\n    int end_node = 0;\n    ll err = (1LL << 60);\n    ll approx_cost = (1LL << 60);\n};\n\nint N, Lw;\nvector<int> T;\n\n// ---------- utility ----------\nstatic inline ll absll(ll x) { return x >= 0 ? x : -x; }\n\nbool betterCand(const Candidate& x, const Candidate& y) {\n    if (x.err != y.err) return x.err < y.err;\n    return x.approx_cost < y.approx_cost;\n}\n\nCandidate make_candidate(const vector<int>& order, const BuildResult& br, const SimResult& sr) {\n    Candidate c;\n    c.order = order;\n    c.a = br.a;\n    c.b = br.b;\n    c.cnt = sr.cnt;\n    c.end_node = sr.end_node;\n    c.err = sr.err;\n    c.approx_cost = br.approx_cost;\n    return c;\n}\n\nvector<int> normalize_order(vector<int> ord) {\n    int pos = find(ord.begin(), ord.end(), 0) - ord.begin();\n    rotate(ord.begin(), ord.begin() + pos, ord.end());\n    return ord;\n}\n\nvector<int> next_from_order(const vector<int>& order) {\n    vector<int> nxt(N);\n    for (int i = 0; i < N; ++i) nxt[order[i]] = order[(i + 1) % N];\n    return nxt;\n}\n\nvector<int> prev_from_order(const vector<int>& order) {\n    vector<int> prv(N);\n    for (int i = 0; i < N; ++i) prv[order[(i + 1) % N]] = order[i];\n    return prv;\n}\n\nll calc_cost(const vector<int>& assign, const vector<int>& item, const vector<int>& need, vector<int>* load_out = nullptr) {\n    vector<int> load(N, 0);\n    for (int i = 0; i < N; ++i) load[assign[i]] += item[i];\n    ll cost = 0;\n    for (int j = 0; j < N; ++j) cost += absll((ll)load[j] - need[j]);\n    if (load_out) *load_out = load;\n    return cost;\n}\n\n// ---------- fast cycle-order surrogate cost ----------\nll edge_cost_fast(int i, int j, const vector<int>& est) {\n    ll half_from_i = (est[i] + 1) / 2;                // odd chunk if i is predecessor of j\n    ll cap_j = T[j] - (j == 0 ? 1 : 0);               // target remaining after initial visit\n    if (cap_j < 0) cap_j = 0;\n    ll ideal = (cap_j + 1) / 2;                       // roughly half should come from predecessor\n    ll over = max(0LL, half_from_i - cap_j);          // impossible oversupply is especially bad\n    ll sim = absll((ll)est[i] - est[j]);              // similar targets often pair well\n    return over * 20 + absll(half_from_i - ideal) * 4 + sim;\n}\n\nll order_cost_fast(const vector<int>& ord, const vector<int>& est) {\n    ll c = 0;\n    for (int k = 0; k < N; ++k) {\n        int i = ord[k];\n        int j = ord[(k + 1) % N];\n        c += edge_cost_fast(i, j, est);\n    }\n    return c;\n}\n\nvector<int> mutate_order_random(const vector<int>& ord, mt19937& rng) {\n    vector<int> res = ord;\n    int op = (int)(rng() % 3);\n\n    if (op == 0) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) swap(res[x], res[y]);\n    } else if (op == 1) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) {\n            int v = res[x];\n            res.erase(res.begin() + x);\n            if (y > x) --y;\n            res.insert(res.begin() + y, v);\n        }\n    } else {\n        int l = 1 + (int)(rng() % (N - 1));\n        int r = 1 + (int)(rng() % (N - 1));\n        if (l > r) swap(l, r);\n        if (l == r) r = min(N - 1, l + 1);\n        reverse(res.begin() + l, res.begin() + r + 1);\n    }\n    return res;\n}\n\nvector<int> optimize_order_fast(vector<int> ord, const vector<int>& est, mt19937& rng, int iters, double temp0) {\n    ord = normalize_order(ord);\n    ll cur = order_cost_fast(ord, est);\n    vector<int> best = ord;\n    ll bestc = cur;\n\n    uniform_real_distribution<double> U(0.0, 1.0);\n    double temp = temp0;\n    double temp1 = 1.0;\n    double alpha = pow(temp1 / temp0, 1.0 / max(1, iters));\n\n    for (int iter = 0; iter < iters; ++iter) {\n        vector<int> cand = mutate_order_random(ord, rng);\n        ll nc = order_cost_fast(cand, est);\n        if (nc < cur || U(rng) < exp((double)(cur - nc) / max(1.0, temp))) {\n            ord.swap(cand);\n            cur = nc;\n            if (cur < bestc) {\n                bestc = cur;\n                best = ord;\n            }\n        }\n        temp *= alpha;\n    }\n    return best;\n}\n\n// ---------- assignment builders ----------\nvector<int> init_dp_partition(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N), tgt_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    iota(tgt_ord.begin(), tgt_ord.end(), 0);\n\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] < item[b];\n        return a < b;\n    });\n    sort(tgt_ord.begin(), tgt_ord.end(), [&](int a, int b) {\n        if (need[a] != need[b]) return need[a] < need[b];\n        return a < b;\n    });\n\n    vector<ll> pref(N + 1, 0);\n    for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + item[src_ord[i]];\n\n    const ll INF = (1LL << 60);\n    vector<vector<ll>> dp(N + 1, vector<ll>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int k = 0; k < N; ++k) {\n        for (int i = 0; i <= N; ++i) {\n            if (dp[k][i] >= INF) continue;\n            for (int j = i; j <= N; ++j) {\n                ll segsum = pref[j] - pref[i];\n                ll nd = dp[k + 1][j] + 0; // keep compiler calm\n                nd = dp[k][i] + absll(segsum - (ll)need[tgt_ord[k]]);\n                if (nd < dp[k + 1][j]) {\n                    dp[k + 1][j] = nd;\n                    par[k + 1][j] = i;\n                }\n            }\n        }\n    }\n\n    vector<int> assign(N, 0);\n    int cur = N;\n    for (int k = N - 1; k >= 0; --k) {\n        int prv = par[k + 1][cur];\n        if (prv < 0) prv = 0;\n        for (int p = prv; p < cur; ++p) assign[src_ord[p]] = tgt_ord[k];\n        cur = prv;\n    }\n    return assign;\n}\n\nvector<int> init_greedy(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] > item[b];\n        return a < b;\n    });\n\n    vector<int> assign(N, 0);\n    vector<int> load(N, 0);\n\n    for (int s : src_ord) {\n        ll best_delta = (1LL << 60);\n        int best_t = 0;\n        for (int t = 0; t < N; ++t) {\n            ll before = absll((ll)load[t] - need[t]);\n            ll after = absll((ll)load[t] + item[s] - need[t]);\n            ll delta = after - before;\n            ll deficit = (ll)need[t] - load[t];\n            ll best_deficit = (ll)need[best_t] - load[best_t];\n            if (delta < best_delta ||\n                (delta == best_delta && deficit > best_deficit) ||\n                (delta == best_delta && deficit == best_deficit && t < best_t)) {\n                best_delta = delta;\n                best_t = t;\n            }\n        }\n        assign[s] = best_t;\n        load[best_t] += item[s];\n    }\n    return assign;\n}\n\nll local_search_assign(vector<int>& assign, const vector<int>& item, const vector<int>& need) {\n    vector<int> load;\n    ll total = calc_cost(assign, item, need, &load);\n\n    const int MAX_IT = 80;\n    for (int iter = 0; iter < MAX_IT; ++iter) {\n        vector<ll> base(N);\n        for (int j = 0; j < N; ++j) base[j] = absll((ll)load[j] - need[j]);\n\n        ll best_delta = 0;\n        int best_kind = 0; // 1=move, 2=swap\n        int bi = -1, bj = -1, bk = -1;\n\n        // moves\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i];\n            int w = item[i];\n            if (w == 0) continue;\n            for (int v = 0; v < N; ++v) if (v != u) {\n                ll delta = 0;\n                delta += absll((ll)load[u] - w - need[u]) - base[u];\n                delta += absll((ll)load[v] + w - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 1;\n                    bi = i; bj = v;\n                }\n            }\n        }\n\n        // swaps\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i];\n            int wi = item[i];\n            for (int k = i + 1; k < N; ++k) {\n                int v = assign[k];\n                if (u == v) continue;\n                int wk = item[k];\n                ll delta = 0;\n                delta += absll((ll)load[u] - wi + wk - need[u]) - base[u];\n                delta += absll((ll)load[v] - wk + wi - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 2;\n                    bi = i; bk = k;\n                }\n            }\n        }\n\n        if (best_kind == 0) break;\n\n        if (best_kind == 1) {\n            int i = bi, v = bj;\n            int u = assign[i];\n            int w = item[i];\n            load[u] -= w;\n            load[v] += w;\n            assign[i] = v;\n            total += best_delta;\n        } else {\n            int i = bi, k = bk;\n            int u = assign[i], v = assign[k];\n            int wi = item[i], wk = item[k];\n            load[u] = load[u] - wi + wk;\n            load[v] = load[v] - wk + wi;\n            swap(assign[i], assign[k]);\n            total += best_delta;\n        }\n    }\n\n    return total;\n}\n\n// ---------- build graph from a fixed cycle order ----------\nBuildResult build_graph(const vector<int>& order, const vector<int>& est_cnt, bool exact_end, int end_node) {\n    vector<int> nxt = next_from_order(order);\n    vector<int> prv = prev_from_order(order);\n\n    vector<int> out = est_cnt;\n    if (exact_end && 0 <= end_node && end_node < N) out[end_node]--;\n\n    vector<int> fixed_a(N), item_b(N), need(N);\n    for (int i = 0; i < N; ++i) {\n        if (out[i] < 0) out[i] = 0;\n        fixed_a[i] = (out[i] + 1) / 2; // odd departures -> a_i\n        item_b[i] = out[i] / 2;        // even departures -> b_i\n    }\n\n    for (int j = 0; j < N; ++j) {\n        need[j] = T[j] - (j == 0 ? 1 : 0) - fixed_a[prv[j]];\n    }\n\n    vector<int> assign1 = init_dp_partition(item_b, need);\n    ll cost1 = local_search_assign(assign1, item_b, need);\n\n    vector<int> assign2 = init_greedy(item_b, need);\n    ll cost2 = local_search_assign(assign2, item_b, need);\n\n    vector<int> best_assign;\n    ll best_cost;\n    if (cost1 <= cost2) {\n        best_assign = move(assign1);\n        best_cost = cost1;\n    } else {\n        best_assign = move(assign2);\n        best_cost = cost2;\n    }\n\n    BuildResult res;\n    res.a = move(nxt);\n    res.b = move(best_assign);\n    res.approx_cost = best_cost;\n    return res;\n}\n\n// ---------- exact simulation ----------\nSimResult simulate_graph(const vector<int>& a, const vector<int>& b) {\n    vector<int> cnt(N, 0);\n    int cur = 0;\n    int end_node = 0;\n\n    for (int week = 0; week < Lw; ++week) {\n        ++cnt[cur];\n        end_node = cur;\n        if (week + 1 == Lw) break;\n        cur = (cnt[cur] & 1) ? a[cur] : b[cur];\n    }\n\n    ll err = 0;\n    for (int i = 0; i < N; ++i) err += absll((ll)cnt[i] - T[i]);\n    return {cnt, end_node, err};\n}\n\nCandidate evaluate_order(const vector<int>& order, const vector<int>& init_est, bool exact_end_init, int end_init, int refine_rounds) {\n    BuildResult br = build_graph(order, init_est, exact_end_init, end_init);\n    SimResult sr = simulate_graph(br.a, br.b);\n    Candidate best = make_candidate(order, br, sr);\n    Candidate cur = best;\n\n    for (int it = 0; it < refine_rounds; ++it) {\n        BuildResult br2 = build_graph(order, cur.cnt, true, cur.end_node);\n        SimResult sr2 = simulate_graph(br2.a, br2.b);\n        Candidate nxt = make_candidate(order, br2, sr2);\n        if (betterCand(nxt, cur)) {\n            cur = nxt;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- cycle order generators ----------\nvector<int> sorted_order(bool desc) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return desc ? (T[a] > T[b]) : (T[a] < T[b]);\n        return a < b;\n    });\n    return normalize_order(ord);\n}\n\nvector<int> nearest_neighbor_order(int start, bool half_cost_mode) {\n    vector<int> ord;\n    vector<int> used(N, 0);\n    ord.reserve(N);\n    ord.push_back(start);\n    used[start] = 1;\n    int cur = start;\n\n    for (int step = 1; step < N; ++step) {\n        int best = -1;\n        ll best1 = (1LL << 60), best2 = (1LL << 60);\n\n        for (int v = 0; v < N; ++v) if (!used[v]) {\n            ll c1, c2;\n            if (!half_cost_mode) {\n                c1 = absll((ll)T[cur] - T[v]);\n                c2 = 0;\n            } else {\n                c1 = max(0, (T[cur] + 1) / 2 - T[v]);\n                c2 = absll((ll)T[cur] - T[v]);\n            }\n            if (best == -1 || c1 < best1 || (c1 == best1 && c2 < best2) || (c1 == best1 && c2 == best2 && v < best)) {\n                best = v;\n                best1 = c1;\n                best2 = c2;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return normalize_order(ord);\n}\n\nvector<int> median_out_order(const vector<int>& base_sorted) {\n    vector<int> ord;\n    ord.reserve(N);\n    int mid = N / 2;\n    ord.push_back(base_sorted[mid]);\n    for (int d = 1; (int)ord.size() < N; ++d) {\n        if (mid - d >= 0) ord.push_back(base_sorted[mid - d]);\n        if ((int)ord.size() >= N) break;\n        if (mid + d < N) ord.push_back(base_sorted[mid + d]);\n    }\n    return normalize_order(ord);\n}\n\nvector<int> alternating_low_high_order() {\n    vector<int> s(N);\n    iota(s.begin(), s.end(), 0);\n    sort(s.begin(), s.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return T[a] < T[b];\n        return a < b;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    int l = 0, r = N - 1;\n    while (l <= r) {\n        ord.push_back(s[l++]);\n        if (l <= r) ord.push_back(s[r--]);\n    }\n    return normalize_order(ord);\n}\n\nvoid add_order_if_new(vector<vector<int>>& orders, set<vector<int>>& seen, vector<int> ord) {\n    ord = normalize_order(ord);\n    if (seen.insert(ord).second) orders.push_back(ord);\n}\n\n// ---------- exact local improvement on order ----------\nCandidate improve_candidate_order(Candidate start, mt19937& rng) {\n    Candidate best = start;\n    Candidate cur = start;\n    set<vector<int>> tried;\n    tried.insert(cur.order);\n\n    // one larger jump using the fast surrogate around the current candidate\n    {\n        auto jumped = optimize_order_fast(cur.order, cur.cnt, rng, 900, 2500.0);\n        if (!tried.count(jumped)) {\n            tried.insert(jumped);\n            Candidate cand = evaluate_order(jumped, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, cur)) cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n\n    // exact hill climbing with filtered random neighbors\n    for (int iter = 0; iter < 14; ++iter) {\n        vector<int> chosen;\n        ll best_fast = (1LL << 60);\n\n        for (int t = 0; t < 5; ++t) {\n            auto m = mutate_order_random(cur.order, rng);\n            if (tried.count(m)) continue;\n            ll fc = order_cost_fast(m, cur.cnt);\n            if (fc < best_fast) {\n                best_fast = fc;\n                chosen = move(m);\n            }\n        }\n        if (chosen.empty()) continue;\n        tried.insert(chosen);\n\n        Candidate cand = evaluate_order(chosen, cur.cnt, true, cur.end_node, 1);\n        if (betterCand(cand, cur)) {\n            cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> Lw;\n    T.resize(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    mt19937 rng(123456789);\n\n    vector<vector<int>> seeds;\n    {\n        vector<int> desc = sorted_order(true);\n        vector<int> asc = sorted_order(false);\n\n        vector<int> orig(N), revorig(N);\n        iota(orig.begin(), orig.end(), 0);\n        revorig = orig;\n        reverse(revorig.begin(), revorig.end());\n\n        int imin = min_element(T.begin(), T.end()) - T.begin();\n        int imax = max_element(T.begin(), T.end()) - T.begin();\n\n        seeds.push_back(desc);\n        seeds.push_back(asc);\n        seeds.push_back(normalize_order(orig));\n        seeds.push_back(normalize_order(revorig));\n        seeds.push_back(nearest_neighbor_order(0, false));\n        seeds.push_back(nearest_neighbor_order(0, true));\n        seeds.push_back(nearest_neighbor_order(imin, false));\n        seeds.push_back(nearest_neighbor_order(imax, false));\n        seeds.push_back(nearest_neighbor_order(imax, true));\n        seeds.push_back(median_out_order(desc));\n        {\n            auto tmp = median_out_order(desc);\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n        seeds.push_back(alternating_low_high_order());\n        {\n            auto tmp = alternating_low_high_order();\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n    }\n\n    vector<vector<int>> orders;\n    set<vector<int>> seen;\n\n    for (auto s : seeds) add_order_if_new(orders, seen, s);\n    for (auto s : seeds) {\n        auto opt = optimize_order_fast(s, T, rng, 1200, 3000.0);\n        add_order_if_new(orders, seen, opt);\n    }\n\n    // random perturb + optimize around good seeds\n    for (int rep = 0; rep < 10; ++rep) {\n        auto tmp = seeds[rng() % seeds.size()];\n        int mv = 3 + (rng() % 4);\n        for (int k = 0; k < mv; ++k) tmp = mutate_order_random(tmp, rng);\n        tmp = optimize_order_fast(tmp, T, rng, 900, 2200.0);\n        add_order_if_new(orders, seen, tmp);\n    }\n\n    // rank by surrogate cost and evaluate the best few exactly\n    vector<pair<ll, int>> rank_idx;\n    rank_idx.reserve((int)orders.size());\n    for (int i = 0; i < (int)orders.size(); ++i) {\n        rank_idx.push_back({order_cost_fast(orders[i], T), i});\n    }\n    sort(rank_idx.begin(), rank_idx.end());\n\n    int M = min<int>(20, rank_idx.size());\n    vector<Candidate> cand_list;\n    cand_list.reserve(M);\n\n    for (int z = 0; z < M; ++z) {\n        int idx = rank_idx[z].second;\n        Candidate cand = evaluate_order(orders[idx], T, false, -1, 2);\n        cand_list.push_back(move(cand));\n    }\n\n    sort(cand_list.begin(), cand_list.end(), [&](const Candidate& x, const Candidate& y) {\n        return betterCand(x, y);\n    });\n\n    Candidate best = cand_list[0];\n\n    // exact order refinement around the best candidates\n    int topK = min<int>(4, cand_list.size());\n    for (int i = 0; i < topK; ++i) {\n        Candidate improved = improve_candidate_order(cand_list[i], rng);\n        if (betterCand(improved, best)) best = improved;\n    }\n\n    // one more fixed-point rebuild on the final best candidate\n    {\n        Candidate fin = evaluate_order(best.order, best.cnt, true, best.end_node, 2);\n        if (betterCand(fin, best)) best = fin;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << best.a[i] << ' ' << best.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 800;\nstatic constexpr double INF = 1e100;\n\nint N, M, Q, L, Wv;\nvector<int> G;\nstatic int SX[MAXN], SY[MAXN];          // doubled centers\nstatic uint64_t KEY_[MAXN];             // Morton key\nstatic double distMat[MAXN][MAXN];\n\nstruct GroupItem {\n    int size;\n    int id;\n};\n\nstruct Plan {\n    vector<int> order;   // order of cities in the group\n    vector<int> adds;    // each block adds t new cities; block size = t + 1\n    double estCost = 0.0;\n};\n\nuint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\n\nuint64_t mortonEncode(uint32_t x, uint32_t y) {\n    return (uint64_t)part1by1(x) | ((uint64_t)part1by1(y) << 1);\n}\n\nbool cmpMortonCity(int a, int b) {\n    if (KEY_[a] != KEY_[b]) return KEY_[a] < KEY_[b];\n    return a < b;\n}\nbool cmpXCity(int a, int b) {\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    return a < b;\n}\nbool cmpYCity(int a, int b) {\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\n\ndouble mst_cost_slice(const vector<int>& ord, int st, int len) {\n    if (len <= 1) return 0.0;\n    double md[16];\n    bool used[16];\n    for (int i = 0; i < len; i++) {\n        md[i] = INF;\n        used[i] = false;\n    }\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < len; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < len; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = true;\n        total += bv;\n        int u = ord[st + bi];\n        for (int j = 0; j < len; j++) {\n            if (!used[j]) {\n                double w = distMat[u][ord[st + j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\ndouble optimize_chain_cost_only(const vector<int>& ord) {\n    int g = (int)ord.size();\n    if (g <= 1) return 0.0;\n    if (g == 2) return distMat[ord[0]][ord[1]];\n    if (g <= L) return mst_cost_slice(ord, 0, g);\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);  // minimal number of blocks\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = distMat[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<double> dp(remain + 1, INF), ndp(remain + 1, INF);\n    dp[0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        fill(ndp.begin(), ndp.end(), INF);\n        for (int p = 0; p <= remain; p++) {\n            if (dp[p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[p] + wcost[p][t];\n                if (cand < ndp[np]) ndp[np] = cand;\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    return dp[remain];\n}\n\npair<double, vector<int>> optimize_chain_reconstruct(const vector<int>& ord) {\n    int g = (int)ord.size();\n    if (g <= 1) return {0.0, {}};\n    if (g == 2) return {distMat[ord[0]][ord[1]], {}};\n    if (g <= L) return {mst_cost_slice(ord, 0, g), {}};\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = distMat[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<vector<double>> dp(K + 1, vector<double>(remain + 1, INF));\n    vector<vector<int>> par(K + 1, vector<int>(remain + 1, -1));\n    dp[0][0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        for (int p = 0; p <= remain; p++) {\n            if (dp[b][p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[b][p] + wcost[p][t];\n                if (cand < dp[b + 1][np]) {\n                    dp[b + 1][np] = cand;\n                    par[b + 1][np] = t;\n                }\n            }\n        }\n    }\n\n    vector<int> adds;\n    int p = remain;\n    for (int b = K; b >= 1; b--) {\n        int t = par[b][p];\n        if (t < 0) break;\n        adds.push_back(t);\n        p -= t;\n    }\n    reverse(adds.begin(), adds.end());\n    return {dp[K][remain], adds};\n}\n\nvector<int> sort_morton(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpMortonCity);\n    return v;\n}\nvector<int> sort_x(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpXCity);\n    return v;\n}\nvector<int> sort_y(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpYCity);\n    return v;\n}\n\nvector<int> nn_order(const vector<int>& group, int startCity) {\n    int g = (int)group.size();\n    vector<char> used(N, 0);\n    vector<int> ord;\n    ord.reserve(g);\n    int cur = startCity;\n    used[cur] = 1;\n    ord.push_back(cur);\n\n    for (int step = 1; step < g; step++) {\n        int best = -1;\n        double bestD = INF;\n        for (int v : group) {\n            if (used[v]) continue;\n            double d = distMat[cur][v];\n            if (best == -1 || d < bestD - 1e-12 ||\n                (fabs(d - bestD) <= 1e-12 && cmpMortonCity(v, best))) {\n                best = v;\n                bestD = d;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return ord;\n}\n\ndouble estimate_group_cost(const vector<int>& group) {\n    vector<int> ord = sort_morton(group);\n    return optimize_chain_cost_only(ord);\n}\n\nvector<pair<int,int>> ask(const vector<int>& sub) {\n    cout << \"? \" << sub.size();\n    for (int v : sub) cout << ' ' << v;\n    cout << '\\n';\n    cout.flush();\n\n    vector<pair<int,int>> ret;\n    ret.reserve((int)sub.size() - 1);\n    for (int i = 0; i < (int)sub.size() - 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.push_back({a, b});\n    }\n    return ret;\n}\n\nvoid append_chain_edges(const vector<int>& sub, vector<pair<int,int>>& edges) {\n    for (int i = 1; i < (int)sub.size(); i++) {\n        int a = sub[i - 1], b = sub[i];\n        if (a > b) swap(a, b);\n        edges.push_back({a, b});\n    }\n}\n\nvector<vector<int>> makeContiguous(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n    vector<vector<int>> groups(M);\n    int pos = 0;\n    for (int gid : groupOrder) {\n        groups[gid] = vector<int>(cityOrder.begin() + pos, cityOrder.begin() + pos + G[gid]);\n        pos += G[gid];\n    }\n    return groups;\n}\n\ndouble span_cost(int dx, int dy, int cnt, int mode) {\n    double base = (mode == 0) ? (double)(dx + dy) : sqrt((double)dx * dx + (double)dy * dy);\n    return base * sqrt((double)cnt);\n}\n\nvoid kd_rec(const vector<int>& pts, const vector<GroupItem>& items,\n            vector<vector<int>>& ans, int mode) {\n    if ((int)items.size() == 1) {\n        ans[items[0].id] = pts;\n        return;\n    }\n\n    int n = (int)pts.size();\n    int m = (int)items.size();\n\n    vector<vector<char>> poss(m + 1, vector<char>(n + 1, 0));\n    poss[0][0] = 1;\n    for (int i = 0; i < m; i++) {\n        int sz = items[i].size;\n        for (int s = 0; s <= n; s++) {\n            if (!poss[i][s]) continue;\n            poss[i + 1][s] = 1;\n            if (s + sz <= n) poss[i + 1][s + sz] = 1;\n        }\n    }\n\n    vector<int> ordx = pts, ordy = pts;\n    sort(ordx.begin(), ordx.end(), cmpXCity);\n    sort(ordy.begin(), ordy.end(), cmpYCity);\n\n    vector<int> pxMinY(n), pxMaxY(n), sxMinY(n), sxMaxY(n);\n    vector<int> pyMinX(n), pyMaxX(n), syMinX(n), syMaxX(n);\n\n    for (int i = 0; i < n; i++) {\n        int v = ordx[i];\n        if (i == 0) pxMinY[i] = pxMaxY[i] = SY[v];\n        else {\n            pxMinY[i] = min(pxMinY[i - 1], SY[v]);\n            pxMaxY[i] = max(pxMaxY[i - 1], SY[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordx[i];\n        if (i == n - 1) sxMinY[i] = sxMaxY[i] = SY[v];\n        else {\n            sxMinY[i] = min(sxMinY[i + 1], SY[v]);\n            sxMaxY[i] = max(sxMaxY[i + 1], SY[v]);\n        }\n    }\n\n    for (int i = 0; i < n; i++) {\n        int v = ordy[i];\n        if (i == 0) pyMinX[i] = pyMaxX[i] = SX[v];\n        else {\n            pyMinX[i] = min(pyMinX[i - 1], SX[v]);\n            pyMaxX[i] = max(pyMaxX[i - 1], SX[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordy[i];\n        if (i == n - 1) syMinX[i] = syMaxX[i] = SX[v];\n        else {\n            syMinX[i] = min(syMinX[i + 1], SX[v]);\n            syMaxX[i] = max(syMaxX[i + 1], SX[v]);\n        }\n    }\n\n    double bestScore = INF;\n    int bestS = -1;\n    int bestAxis = 0; // 0:x, 1:y\n\n    for (int s = 1; s < n; s++) {\n        if (!poss[m][s]) continue;\n\n        {\n            int ldx = SX[ordx[s - 1]] - SX[ordx[0]];\n            int ldy = pxMaxY[s - 1] - pxMinY[s - 1];\n            int rdx = SX[ordx[n - 1]] - SX[ordx[s]];\n            int rdy = sxMaxY[s] - sxMinY[s];\n            double score = span_cost(ldx, ldy, s, mode) + span_cost(rdx, rdy, n - s, mode);\n            if (score < bestScore - 1e-9 ||\n                (fabs(score - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n                bestScore = score;\n                bestS = s;\n                bestAxis = 0;\n            }\n        }\n        {\n            int ldy = SY[ordy[s - 1]] - SY[ordy[0]];\n            int ldx = pyMaxX[s - 1] - pyMinX[s - 1];\n            int rdy = SY[ordy[n - 1]] - SY[ordy[s]];\n            int rdx = syMaxX[s] - syMinX[s];\n            double score = span_cost(ldx, ldy, s, mode) + span_cost(rdx, rdy, n - s, mode);\n            if (score < bestScore - 1e-9 ||\n                (fabs(score - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n                bestScore = score;\n                bestS = s;\n                bestAxis = 1;\n            }\n        }\n    }\n\n    if (bestS == -1) {\n        bestS = items[0].size;\n        if (bestS <= 0 || bestS >= n) bestS = n / 2;\n        bestAxis = 0;\n    }\n\n    vector<GroupItem> leftItems, rightItems;\n    int sum = bestS;\n    for (int i = m - 1; i >= 0; i--) {\n        int sz = items[i].size;\n        if (sum >= sz && poss[i][sum - sz]) {\n            leftItems.push_back(items[i]);\n            sum -= sz;\n        } else {\n            rightItems.push_back(items[i]);\n        }\n    }\n    reverse(leftItems.begin(), leftItems.end());\n    reverse(rightItems.begin(), rightItems.end());\n\n    const vector<int>& ord = (bestAxis == 0 ? ordx : ordy);\n    vector<int> leftPts(ord.begin(), ord.begin() + bestS);\n    vector<int> rightPts(ord.begin() + bestS, ord.end());\n\n    kd_rec(leftPts, leftItems, ans, mode);\n    kd_rec(rightPts, rightItems, ans, mode);\n}\n\nvector<vector<int>> makeKD(int mode) {\n    vector<vector<int>> ans(M);\n    vector<int> pts(N);\n    iota(pts.begin(), pts.end(), 0);\n    vector<GroupItem> items(M);\n    for (int i = 0; i < M; i++) items[i] = {G[i], i};\n    kd_rec(pts, items, ans, mode);\n    return ans;\n}\n\nPlan choose_plan(const vector<int>& group) {\n    Plan plan;\n    int g = (int)group.size();\n    if (g == 0) return plan;\n\n    auto ordMort = sort_morton(group);\n    plan.order = ordMort;\n    plan.estCost = optimize_chain_cost_only(ordMort);\n    if (g <= L) return plan;\n\n    auto base = optimize_chain_reconstruct(ordMort);\n    plan.estCost = base.first;\n    plan.adds = base.second;\n\n    auto try_order = [&](const vector<int>& ord) {\n        auto res = optimize_chain_reconstruct(ord);\n        if (res.first < plan.estCost - 1e-9) {\n            plan.estCost = res.first;\n            plan.order = ord;\n            plan.adds = res.second;\n        }\n    };\n\n    {\n        auto v = ordMort;\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n    {\n        auto v = sort_x(group);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n    {\n        auto v = sort_y(group);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n\n    int leftmost = *min_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n    int rightmost = *max_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n\n    {\n        auto v = nn_order(group, leftmost);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n    if (rightmost != leftmost) {\n        auto v = nn_order(group, rightmost);\n        try_order(v);\n        reverse(v.begin(), v.end());\n        try_order(v);\n    }\n\n    return plan;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> Q >> L >> Wv;\n    G.resize(M);\n    for (int i = 0; i < M; i++) cin >> G[i];\n\n    vector<int> lx(N), rx(N), ly(N), ry(N);\n    for (int i = 0; i < N; i++) {\n        cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n        SX[i] = lx[i] + rx[i];\n        SY[i] = ly[i] + ry[i];\n        KEY_[i] = mortonEncode((uint32_t)SX[i], (uint32_t)SY[i]);\n    }\n\n    for (int i = 0; i < N; i++) {\n        distMat[i][i] = 0.0;\n        for (int j = i + 1; j < N; j++) {\n            long long dx = (long long)SX[i] - SX[j];\n            long long dy = (long long)SY[i] - SY[j];\n            double d = sqrt((double)dx * dx + (double)dy * dy);\n            distMat[i][j] = distMat[j][i] = d;\n        }\n    }\n\n    vector<int> groupIdsAsc(M), groupIdsDesc(M);\n    iota(groupIdsAsc.begin(), groupIdsAsc.end(), 0);\n    sort(groupIdsAsc.begin(), groupIdsAsc.end(), [&](int a, int b) {\n        if (G[a] != G[b]) return G[a] < G[b];\n        return a < b;\n    });\n    groupIdsDesc = groupIdsAsc;\n    reverse(groupIdsDesc.begin(), groupIdsDesc.end());\n\n    vector<int> allCities(N);\n    iota(allCities.begin(), allCities.end(), 0);\n\n    vector<int> cityMort = allCities;\n    sort(cityMort.begin(), cityMort.end(), cmpMortonCity);\n\n    vector<int> cityX = allCities;\n    sort(cityX.begin(), cityX.end(), cmpXCity);\n\n    vector<int> cityY = allCities;\n    sort(cityY.begin(), cityY.end(), cmpYCity);\n\n    vector<int> revMort = cityMort;\n    reverse(revMort.begin(), revMort.end());\n\n    double bestScore = INF;\n    vector<vector<int>> bestGroups;\n\n    auto try_candidate = [&](vector<vector<int>> cand) {\n        double sc = 0.0;\n        for (int gid = 0; gid < M; gid++) {\n            sc += estimate_group_cost(cand[gid]);\n            if (sc >= bestScore) break;\n        }\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestGroups = std::move(cand);\n        }\n    };\n\n    try_candidate(makeKD(0));\n    try_candidate(makeKD(1));\n    try_candidate(makeContiguous(cityMort, groupIdsAsc));\n    try_candidate(makeContiguous(cityMort, groupIdsDesc));\n    try_candidate(makeContiguous(revMort, groupIdsAsc));\n    try_candidate(makeContiguous(revMort, groupIdsDesc));\n    try_candidate(makeContiguous(cityX, groupIdsAsc));\n    try_candidate(makeContiguous(cityY, groupIdsAsc));\n\n    vector<Plan> plans(M);\n    for (int gid = 0; gid < M; gid++) {\n        plans[gid] = choose_plan(bestGroups[gid]);\n        if (plans[gid].order.empty()) plans[gid].order = bestGroups[gid];\n    }\n\n    vector<vector<pair<int,int>>> answerEdges(M);\n    int queriesUsed = 0;\n\n    for (int gid = 0; gid < M; gid++) {\n        const auto& ord = plans[gid].order;\n        int g = (int)ord.size();\n        answerEdges[gid].reserve(max(0, g - 1));\n\n        if (g <= 1) continue;\n        if (g == 2) {\n            int a = ord[0], b = ord[1];\n            if (a > b) swap(a, b);\n            answerEdges[gid].push_back({a, b});\n            continue;\n        }\n\n        if (g <= L) {\n            if (queriesUsed < Q) {\n                auto ret = ask(ord);\n                answerEdges[gid].insert(answerEdges[gid].end(), ret.begin(), ret.end());\n                queriesUsed++;\n            } else {\n                append_chain_edges(ord, answerEdges[gid]);\n            }\n        } else {\n            int pos = 0;\n            for (int t : plans[gid].adds) {\n                int msz = t + 1;\n                vector<int> sub(ord.begin() + pos, ord.begin() + pos + msz);\n                if (msz >= 3 && queriesUsed < Q) {\n                    auto ret = ask(sub);\n                    answerEdges[gid].insert(answerEdges[gid].end(), ret.begin(), ret.end());\n                    queriesUsed++;\n                } else {\n                    append_chain_edges(sub, answerEdges[gid]);\n                }\n                pos += t;\n            }\n        }\n\n        for (auto& e : answerEdges[gid]) {\n            if (e.first > e.second) swap(e.first, e.second);\n        }\n        sort(answerEdges[gid].begin(), answerEdges[gid].end());\n    }\n\n    cout << \"!\" << '\\n';\n    for (int gid = 0; gid < M; gid++) {\n        const auto& ord = plans[gid].order;\n        for (int i = 0; i < (int)ord.size(); i++) {\n            if (i) cout << ' ';\n            cout << ord[i];\n        }\n        cout << '\\n';\n        for (auto [a, b] : answerEdges[gid]) {\n            cout << a << ' ' << b << '\\n';\n        }\n    }\n    cout.flush();\n\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 40;\nstatic constexpr int MAXV = 400;\nstatic constexpr int INF = 1e9;\n\nstruct Point {\n    int r, c;\n};\n\nstruct Cmd {\n    char a, d;\n};\n\nstruct Graph {\n    array<uint8_t, MAXV> cnt{};\n    array<array<uint16_t, 8>, MAXV> to{};\n    array<array<uint8_t, 8>, MAXV> act{};\n\n    array<uint8_t, MAXV> rcnt{};\n    array<array<uint16_t, 48>, MAXV> rev{};\n};\n\nstruct Solver {\n    int N, M, V;\n    array<Point, MAXM> pts{};\n    array<int, MAXM> cells{};\n    array<uint8_t, MAXV> special{};\n\n    vector<int> cand[MAXM];\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n    double TL = 1.92;\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n    const char dirC[4] = {'U', 'D', 'L', 'R'};\n\n    using Assign = array<int, MAXM>;\n\n    // scratch\n    Graph g0, g1;\n    array<short, MAXV> dist0{}, dist1{}, dist2{};\n    array<short, MAXV> prevPos{};\n    array<int8_t, MAXV> prevAct{};\n\n    Solver(int N_, int M_, const vector<Point>& in) : N(N_), M(M_), V(N_ * N_), rng(123456789) {\n        for (int i = 0; i < M; i++) pts[i] = in[i];\n        special.fill(0);\n        for (int i = 0; i < M; i++) {\n            cells[i] = id(pts[i].r, pts[i].c);\n            special[cells[i]] = 1;\n        }\n        build_candidates();\n        st = chrono::steady_clock::now();\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    inline bool time_up(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline int id(int r, int c) const { return r * N + c; }\n    inline int row(int v) const { return v / N; }\n    inline int col(int v) const { return v % N; }\n    inline bool inside(int r, int c) const { return 0 <= r && r < N && 0 <= c && c < N; }\n\n    int adj_dir(int from, int to) const {\n        int fr = row(from), fc = col(from);\n        int tr = row(to), tc = col(to);\n        for (int d = 0; d < 4; d++) {\n            if (fr + dr[d] == tr && fc + dc[d] == tc) return d;\n        }\n        return -1;\n    }\n\n    void build_candidates() {\n        for (int k = 1; k < M; k++) {\n            cand[k].clear();\n            cand[k].push_back(-1);\n            int r = pts[k].r, c = pts[k].c;\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                int v = id(nr, nc);\n                // Keep it simple/safe: do not place on start/targets.\n                if (!special[v]) cand[k].push_back(v);\n            }\n            sort(cand[k].begin(), cand[k].end());\n            cand[k].erase(unique(cand[k].begin(), cand[k].end()), cand[k].end());\n        }\n    }\n\n    void build_graph(const array<uint8_t, MAXV>& blocked, Graph& g) {\n        int slU[MAXV], slD[MAXV], slL[MAXV], slR[MAXV];\n\n        g.cnt.fill(0);\n        g.rcnt.fill(0);\n\n        for (int r = 0; r < N; r++) {\n            int lb = -1;\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                if (blocked[v]) lb = c;\n                else slL[v] = id(r, lb + 1);\n            }\n            int rb = N;\n            for (int c = N - 1; c >= 0; c--) {\n                int v = id(r, c);\n                if (blocked[v]) rb = c;\n                else slR[v] = id(r, rb - 1);\n            }\n        }\n\n        for (int c = 0; c < N; c++) {\n            int ub = -1;\n            for (int r = 0; r < N; r++) {\n                int v = id(r, c);\n                if (blocked[v]) ub = r;\n                else slU[v] = id(ub + 1, c);\n            }\n            int db = N;\n            for (int r = N - 1; r >= 0; r--) {\n                int v = id(r, c);\n                if (blocked[v]) db = r;\n                else slD[v] = id(db - 1, c);\n            }\n        }\n\n        for (int p = 0; p < V; p++) {\n            if (blocked[p]) continue;\n            int r = row(p), c = col(p);\n\n            auto add_edge = [&](int to, int act) {\n                if (to == p) return;\n                auto &cc = g.cnt[p];\n                for (int i = 0; i < cc; i++) {\n                    if (g.to[p][i] == to) return;\n                }\n                g.to[p][cc] = (uint16_t)to;\n                g.act[p][cc] = (uint8_t)act;\n                cc++;\n            };\n\n            add_edge(slU[p], 4);\n            add_edge(slD[p], 5);\n            add_edge(slL[p], 6);\n            add_edge(slR[p], 7);\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                int v = id(nr, nc);\n                if (!blocked[v]) add_edge(v, d);\n            }\n        }\n\n        for (int u = 0; u < V; u++) {\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                g.rev[v][g.rcnt[v]++] = (uint16_t)u;\n            }\n        }\n    }\n\n    void bfs_all(const Graph& g, int src, int forbid, array<short, MAXV>& dist) {\n        dist.fill(-1);\n        if (src == forbid) return;\n        int q[MAXV], qh = 0, qt = 0;\n        dist[src] = 0;\n        q[qt++] = src;\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    void bfs_rev_all(const Graph& g, int dst, int forbid, array<short, MAXV>& dist) {\n        dist.fill(-1);\n        if (dst == forbid) return;\n        int q[MAXV], qh = 0, qt = 0;\n        dist[dst] = 0;\n        q[qt++] = dst;\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.rcnt[u]; i++) {\n                int v = g.rev[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    bool bfs_path(const Graph& g, int src, int dst, int forbid, vector<int>& acts) {\n        acts.clear();\n        if (src == dst) return true;\n\n        dist0.fill(-1);\n        prevPos.fill(-1);\n        prevAct.fill(-1);\n\n        if (src == forbid) return false;\n\n        int q[MAXV], qh = 0, qt = 0;\n        dist0[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist0[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist0[v] != -1) continue;\n                dist0[v] = nd;\n                prevPos[v] = (short)u;\n                prevAct[v] = (int8_t)g.act[u][i];\n                if (v == dst) {\n                    qh = qt;\n                    break;\n                }\n                q[qt++] = v;\n            }\n        }\n\n        if (dist0[dst] == -1) return false;\n\n        int cur = dst;\n        while (cur != src) {\n            acts.push_back(prevAct[cur]);\n            cur = prevPos[cur];\n        }\n        reverse(acts.begin(), acts.end());\n        return true;\n    }\n\n    void append_acts(vector<Cmd>& ans, const vector<int>& acts) const {\n        for (int a : acts) {\n            if (a < 4) ans.push_back({'M', dirC[a]});\n            else ans.push_back({'S', dirC[a - 4]});\n        }\n    }\n\n    Cmd alter_cmd(int from, int block_cell) const {\n        int d = adj_dir(from, block_cell);\n        return {'A', dirC[d]};\n    }\n\n    int segment_best_move_cost(array<uint8_t, MAXV>& blocked, int cur, int target, int x) {\n        build_graph(blocked, g0);\n        bfs_all(g0, cur, -1, dist0);\n\n        int best = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n        if (x != -1 && !blocked[x]) {\n            bfs_all(g0, cur, target, dist1);\n\n            blocked[x] = 1;\n            build_graph(blocked, g1);\n            bfs_rev_all(g1, target, -1, dist2);\n            blocked[x] = 0;\n\n            int pre = INF;\n            int xr = row(x), xc = col(x);\n            for (int d = 0; d < 4; d++) {\n                int vr = xr + dr[d], vc = xc + dc[d];\n                if (!inside(vr, vc)) continue;\n                int v = id(vr, vc);\n                if (v == target) continue;\n                if (blocked[v]) continue;\n                if (dist1[v] == -1 || dist2[v] == -1) continue;\n                pre = min(pre, (int)dist1[v] + (int)dist2[v]);\n            }\n            best = min(best, pre);\n        }\n\n        return best;\n    }\n\n    int eval_assignment(const Assign& asg, int cutoff = INF) {\n        array<uint8_t, MAXV> wanted{}, blocked{};\n        wanted.fill(0);\n        blocked.fill(0);\n\n        int uniq = 0;\n        for (int k = 1; k < M; k++) {\n            int x = asg[k];\n            if (x == -1) continue;\n            if (!wanted[x]) {\n                wanted[x] = 1;\n                uniq++;\n            }\n        }\n\n        int total = uniq;\n        if (total >= cutoff) return total;\n\n        int cur = cells[0];\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            int mv = segment_best_move_cost(blocked, cur, target, x);\n            if (mv >= INF) return INF;\n\n            total += mv;\n            if (total >= cutoff) return total;\n\n            if (x != -1) blocked[x] = 1;\n            cur = target;\n        }\n        return total;\n    }\n\n    Assign all_none_assign() const {\n        Assign a;\n        a.fill(-1);\n        return a;\n    }\n\n    Assign heuristic_prev_assign() const {\n        Assign asg;\n        asg.fill(-1);\n        for (int k = 1; k < M; k++) {\n            int cur = cells[k], prv = cells[k - 1];\n            int r = row(cur), c = col(cur);\n            int pr = row(prv), pc = col(prv);\n\n            vector<int> pref;\n            if (abs(pc - c) <= abs(pr - r)) {\n                if (pr <= r) pref = {1, 0, 3, 2};\n                else         pref = {0, 1, 2, 3};\n            } else {\n                if (pc <= c) pref = {3, 2, 1, 0};\n                else         pref = {2, 3, 0, 1};\n            }\n\n            int chosen = -1;\n            for (int pd : pref) {\n                for (int x : cand[k]) {\n                    if (x == -1) continue;\n                    if (adj_dir(cur, x) == pd) {\n                        chosen = x;\n                        break;\n                    }\n                }\n                if (chosen != -1) break;\n            }\n            asg[k] = chosen;\n        }\n        return asg;\n    }\n\n    Assign greedy_init() {\n        Assign asg;\n        asg.fill(-1);\n\n        array<uint8_t, MAXV> used{}, blocked{};\n        used.fill(0);\n        blocked.fill(0);\n\n        int cur = cells[0];\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int bestx = -1;\n            int bestScore = INF;\n\n            for (int x : cand[k]) {\n                int mv = segment_best_move_cost(blocked, cur, target, x);\n                if (mv >= INF) continue;\n                int extra = (x != -1 && !used[x]) ? 1 : 0;\n                int sc = mv + extra;\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestx = x;\n                }\n            }\n\n            asg[k] = bestx;\n            if (bestx != -1) {\n                used[bestx] = 1;\n                blocked[bestx] = 1;\n            }\n            cur = target;\n        }\n        return asg;\n    }\n\n    Assign random_init() {\n        Assign asg;\n        asg.fill(-1);\n        for (int k = 1; k < M; k++) {\n            if (cand[k].size() == 1) {\n                asg[k] = -1;\n                continue;\n            }\n            int sz = (int)cand[k].size();\n            int pick = (int)(rng() % (sz + 2));\n            if (pick >= sz) asg[k] = -1;\n            else asg[k] = cand[k][pick];\n        }\n        return asg;\n    }\n\n    pair<Assign, int> hill_climb(Assign asg, int curScore) {\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 1);\n\n        int pass = 0;\n        while (!time_up(0.06) && pass < 8) {\n            pass++;\n            shuffle(order.begin(), order.end(), rng);\n\n            bool changed = false;\n            bool strict = false;\n\n            for (int k : order) {\n                if (time_up(0.06)) break;\n\n                int old = asg[k];\n                int bestx = old;\n                int bestScore = curScore;\n\n                for (int x : cand[k]) {\n                    if (x == old) continue;\n                    asg[k] = x;\n                    int sc = eval_assignment(asg, bestScore);\n                    if (sc < bestScore || (sc == bestScore && x != old && (rng() & 7) == 0)) {\n                        bestScore = sc;\n                        bestx = x;\n                    }\n                }\n\n                asg[k] = bestx;\n                if (bestx != old) {\n                    changed = true;\n                    if (bestScore < curScore) strict = true;\n                    curScore = bestScore;\n                }\n            }\n\n            if (!changed) break;\n            if (!strict && pass >= 3) break;\n        }\n\n        return {asg, curScore};\n    }\n\n    vector<Cmd> build_answer(const Assign& asg) {\n        vector<Cmd> ans;\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        int cur = cells[0];\n        vector<int> acts;\n\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            build_graph(blocked, g0);\n            bfs_all(g0, cur, -1, dist0);\n            int direct = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            int pre = INF, bestV = -1;\n\n            if (x != -1 && !blocked[x]) {\n                bfs_all(g0, cur, target, dist1);\n\n                blocked[x] = 1;\n                build_graph(blocked, g1);\n                bfs_rev_all(g1, target, -1, dist2);\n                blocked[x] = 0;\n\n                int xr = row(x), xc = col(x);\n                for (int d = 0; d < 4; d++) {\n                    int vr = xr + dr[d], vc = xc + dc[d];\n                    if (!inside(vr, vc)) continue;\n                    int v = id(vr, vc);\n                    if (v == target) continue;\n                    if (blocked[v]) continue;\n                    if (dist1[v] == -1 || dist2[v] == -1) continue;\n                    int sc = (int)dist1[v] + (int)dist2[v];\n                    if (sc < pre) {\n                        pre = sc;\n                        bestV = v;\n                    }\n                }\n            }\n\n            bool use_pre = (pre < direct);\n\n            if (!use_pre) {\n                if (!bfs_path(g0, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n\n                if (x != -1 && !blocked[x]) {\n                    ans.push_back(alter_cmd(cur, x));\n                    blocked[x] = 1;\n                }\n            } else {\n                if (!bfs_path(g0, cur, bestV, target, acts)) return {};\n                append_acts(ans, acts);\n                cur = bestV;\n\n                ans.push_back(alter_cmd(cur, x));\n                blocked[x] = 1;\n\n                build_graph(blocked, g1);\n                if (!bfs_path(g1, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n            }\n        }\n\n        return ans;\n    }\n\n    pair<bool, int> simulate(const vector<Cmd>& ans) const {\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        int cur = cells[0];\n        int t = 1;\n\n        auto dir_idx = [&](char d) -> int {\n            if (d == 'U') return 0;\n            if (d == 'D') return 1;\n            if (d == 'L') return 2;\n            return 3;\n        };\n\n        for (auto &cmd : ans) {\n            int d = dir_idx(cmd.d);\n            if (cmd.a == 'M') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                if (blocked[v]) return {false, (int)ans.size()};\n                cur = v;\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'S') {\n                int rr = row(cur), cc = col(cur);\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int v = id(nr, nc);\n                    if (blocked[v]) break;\n                    rr = nr;\n                    cc = nc;\n                }\n                cur = id(rr, cc);\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'A') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                blocked[v] ^= 1;\n            } else {\n                return {false, (int)ans.size()};\n            }\n        }\n\n        bool ok = (t == M && (int)ans.size() <= 2 * N * M);\n        return {ok, (int)ans.size()};\n    }\n\n    vector<Cmd> solve() {\n        Assign bestAsg = all_none_assign();\n        int bestScore = eval_assignment(bestAsg);\n\n        vector<Assign> seeds;\n        seeds.push_back(bestAsg);\n        seeds.push_back(heuristic_prev_assign());\n        seeds.push_back(greedy_init());\n        for (int i = 0; i < 3; i++) seeds.push_back(random_init());\n\n        for (auto seed : seeds) {\n            if (time_up(0.25)) break;\n            int sc = eval_assignment(seed);\n            auto res = hill_climb(seed, sc);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n        }\n\n        int iter = 0;\n        while (!time_up(0.08)) {\n            Assign cur;\n            if (iter < 4) cur = random_init();\n            else cur = bestAsg;\n\n            int changes = 1 + (rng() % 5);\n            for (int t = 0; t < changes; t++) {\n                int k = 1 + (rng() % (M - 1));\n                int idx = (int)(rng() % cand[k].size());\n                cur[k] = cand[k][idx];\n            }\n\n            int sc = eval_assignment(cur);\n            auto res = hill_climb(cur, sc);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n            iter++;\n        }\n\n        vector<Cmd> ans = build_answer(bestAsg);\n        auto [ok, len] = simulate(ans);\n        if (!ok) {\n            Assign none = all_none_assign();\n            ans = build_answer(none);\n            auto [ok2, len2] = simulate(ans);\n            if (!ok2) {\n                ans.clear();\n                int cur = cells[0];\n                for (int i = 1; i < M; i++) {\n                    int tr = row(cells[i]), tc = col(cells[i]);\n                    int cr = row(cur), cc = col(cur);\n                    while (cr < tr) ans.push_back({'M', 'D'}), cr++;\n                    while (cr > tr) ans.push_back({'M', 'U'}), cr--;\n                    while (cc < tc) ans.push_back({'M', 'R'}), cc++;\n                    while (cc > tc) ans.push_back({'M', 'L'}), cc--;\n                    cur = cells[i];\n                }\n            }\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<Point> pts(M);\n    for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n    Solver solver(N, M, pts);\n    vector<Cmd> ans = solver.solve();\n\n    for (auto &c : ans) {\n        cout << c.a << ' ' << c.d << '\\n';\n    }\n    return 0;\n}"},"4":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ld = long double;\nstatic constexpr int BOARD = 10000;\nstatic constexpr ld INF_CAP = 1e30L;\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n    int area() const { return (r - l) * (t - b); }\n};\n\nenum Action {\n    EXP_L = 0,\n    EXP_R = 1,\n    EXP_B = 2,\n    EXP_T = 3,\n    SHR_L = 4,\n    SHR_R = 5,\n    SHR_B = 6,\n    SHR_T = 7\n};\n\nstatic constexpr int MASK_EXP =\n    (1 << EXP_L) | (1 << EXP_R) | (1 << EXP_B) | (1 << EXP_T);\nstatic constexpr int MASK_SHR =\n    (1 << SHR_L) | (1 << SHR_R) | (1 << SHR_B) | (1 << SHR_T);\nstatic constexpr int MASK_ALL = MASK_EXP | MASK_SHR;\n\nstruct Move {\n    bool valid = false;\n    int action = 0;\n    int delta = 0;\n    int freecap = 0;\n    int prio = 0;\n    ld gain = 0;\n    ld sec = 0;\n};\n\nstruct PairCand {\n    bool valid = false;\n    int i = -1, j = -1;\n    Rect ri, rj;\n    ld gain = 0;\n    ld sec = 0;\n};\n\nstruct Params {\n    vector<ld> caps;\n    int order_mode = 0;\n    bool reverse_axis = false;\n    array<int, 8> action_prio{};\n};\n\nstruct BSPParams {\n    ld err_w = 0.5L;\n    ld aspect_w = 0.02L;\n    ld step_w = 0.01L;\n    int orient_bias = 0; // -1: horizontal, +1: vertical\n    int top_try = 8;\n    bool smart_bias = true;\n};\n\nstruct SplitCand {\n    bool vertical = true;\n    int cut = 0;\n    vector<int> left, right;\n    ld score = 0;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int mod) {\n        return (int)(next_u64() % (uint64_t)mod);\n    }\n    ld uniform() {\n        return (next_u64() >> 11) * (1.0L / (1ULL << 53));\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n};\n\nstruct Solver {\n    int n;\n    vector<int> xs, ys, rs;\n    vector<ld> sqrs;\n    vector<int> nearest_idx;\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    static bool overlap1d(int l1, int r1, int l2, int r2) {\n        return max(l1, l2) < min(r1, r2);\n    }\n\n    static int ceil_div_int(int a, int b) {\n        return (a + b - 1) / b;\n    }\n\n    ld satisfaction(ld need, ld area) const {\n        if (need <= 0 || area <= 0) return 0;\n        ld t = min(need, area) / max(need, area);\n        ld u = 1.0L - t;\n        return 1.0L - u * u;\n    }\n\n    ld total_score(const vector<Rect>& rects) const {\n        ld res = 0;\n        for (int i = 0; i < n; ++i) res += satisfaction((ld)rs[i], (ld)rects[i].area());\n        return res;\n    }\n\n    long long occupied_area(const vector<Rect>& rects) const {\n        long long s = 0;\n        for (auto &r : rects) s += r.area();\n        return s;\n    }\n\n    vector<Rect> initial_rects() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; ++i) rects[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n        return rects;\n    }\n\n    void apply_move(Rect& rc, int action, int delta) const {\n        switch (action) {\n            case EXP_L: rc.l -= delta; break;\n            case EXP_R: rc.r += delta; break;\n            case EXP_B: rc.b -= delta; break;\n            case EXP_T: rc.t += delta; break;\n            case SHR_L: rc.l += delta; break;\n            case SHR_R: rc.r -= delta; break;\n            case SHR_B: rc.b += delta; break;\n            case SHR_T: rc.t -= delta; break;\n        }\n    }\n\n    ld rect_sec_metric(int i, const Rect& rc) const {\n        int w = rc.r - rc.l;\n        int h = rc.t - rc.b;\n        int area = w * h;\n        int need = rs[i];\n        int nL = xs[i] - rc.l;\n        int nR = rc.r - (xs[i] + 1);\n        int nB = ys[i] - rc.b;\n        int nT = rc.t - (ys[i] + 1);\n        ld aspect = (ld)max(w, h) / (ld)min(w, h);\n        ld imbalance = (ld)(abs(nL - nR) + abs(nB - nT)) / (ld)(w + h);\n        ld err = fabsl((ld)area - (ld)need) / (ld)need;\n        return err + 0.01L * aspect + 0.02L * imbalance;\n    }\n\n    bool better_move(const Move& a, const Move& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const ld EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        if (a.delta < b.delta) return true;\n        if (a.delta > b.delta) return false;\n        if (a.freecap > b.freecap) return true;\n        if (a.freecap < b.freecap) return false;\n        return a.prio < b.prio;\n    }\n\n    bool better_pair(const PairCand& a, const PairCand& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const ld EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        return make_pair(a.i, a.j) < make_pair(b.i, b.j);\n    }\n\n    void compute_expand_limits(int i, const vector<Rect>& rects,\n                               int& maxL, int& maxR, int& maxB, int& maxT) const {\n        const Rect& a = rects[i];\n        int limL = 0, limR = BOARD, limB = 0, limT = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& o = rects[j];\n            if (overlap1d(a.b, a.t, o.b, o.t)) {\n                if (o.r <= a.l) limL = max(limL, o.r);\n                if (o.l >= a.r) limR = min(limR, o.l);\n            }\n            if (overlap1d(a.l, a.r, o.l, o.r)) {\n                if (o.t <= a.b) limB = max(limB, o.t);\n                if (o.b >= a.t) limT = min(limT, o.b);\n            }\n        }\n        maxL = a.l - limL;\n        maxR = limR - a.r;\n        maxB = a.b - limB;\n        maxT = limT - a.t;\n    }\n\n    static void add_target_lengths(vector<int>& v, ld target, int cur, bool expand_mode) {\n        const ld eps = 1e-12L;\n        int f = (int)floor(target + eps);\n        int c = (int)ceil(target - eps);\n        if (expand_mode) {\n            if (f > cur) v.push_back(f);\n            if (c > cur) v.push_back(c);\n        } else {\n            if (f >= 1 && f < cur) v.push_back(f);\n            if (c >= 1 && c < cur) v.push_back(c);\n        }\n    }\n\n    Move best_move_for_rect(int i, const vector<Rect>& rects,\n                            ld shape_cap, bool aggressive,\n                            const array<int, 8>& prio_map,\n                            int allowed_mask) const {\n        const Rect& cur = rects[i];\n        int w = cur.r - cur.l;\n        int h = cur.t - cur.b;\n        int area = w * h;\n        int need = rs[i];\n        ld cur_sat = satisfaction((ld)need, (ld)area);\n\n        int maxL, maxR, maxB, maxT;\n        compute_expand_limits(i, rects, maxL, maxR, maxB, maxT);\n\n        int marginL = xs[i] - cur.l;\n        int marginR = cur.r - (xs[i] + 1);\n        int marginB = ys[i] - cur.b;\n        int marginT = cur.t - (ys[i] + 1);\n\n        vector<Move> cands;\n\n        auto push_candidate = [&](int action, int delta, int freecap) {\n            if (!(allowed_mask & (1 << action))) return;\n            if (delta <= 0) return;\n            for (const auto& mv : cands) {\n                if (mv.action == action && mv.delta == delta) return;\n            }\n            Rect nr = cur;\n            apply_move(nr, action, delta);\n            int nw = nr.r - nr.l;\n            int nh = nr.t - nr.b;\n            int ns = nw * nh;\n            ld g = satisfaction((ld)need, (ld)ns) - cur_sat;\n            if (g <= 1e-18L) return;\n\n            int nL = xs[i] - nr.l;\n            int nR = nr.r - (xs[i] + 1);\n            int nB = ys[i] - nr.b;\n            int nT = nr.t - (ys[i] + 1);\n\n            ld aspect = (ld)max(nw, nh) / (ld)min(nw, nh);\n            ld imbalance = (ld)(abs(nL - nR) + abs(nB - nT)) / (ld)(nw + nh);\n            ld err = fabsl((ld)ns - (ld)need) / (ld)need;\n            ld sec = err + 0.01L * aspect + 0.02L * imbalance;\n\n            Move mv;\n            mv.valid = true;\n            mv.action = action;\n            mv.delta = delta;\n            mv.freecap = freecap;\n            mv.prio = prio_map[action];\n            mv.gain = g;\n            mv.sec = sec;\n            cands.push_back(mv);\n        };\n\n        if (area < need) {\n            ld exactW = (ld)need / (ld)h;\n            ld limitedW = min(exactW, sqrs[i] * shape_cap);\n            vector<int> wtars;\n            add_target_lengths(wtars, limitedW, w, true);\n            add_target_lengths(wtars, exactW, w, true);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_expand_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = Wtar - w;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactW - 1e-12L) > w + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactW - (ld)w - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side(EXP_L, maxL);\n            gen_expand_side(EXP_R, maxR);\n\n            ld exactH = (ld)need / (ld)w;\n            ld limitedH = min(exactH, sqrs[i] * shape_cap);\n            vector<int> htars;\n            add_target_lengths(htars, limitedH, h, true);\n            add_target_lengths(htars, exactH, h, true);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_expand_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = Htar - h;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactH - 1e-12L) > h + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactH - (ld)h - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side_v(EXP_B, maxB);\n            gen_expand_side_v(EXP_T, maxT);\n        } else if (area > need) {\n            ld exactW = (ld)need / (ld)h;\n            vector<int> wtars;\n            add_target_lengths(wtars, exactW, w, false);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_shrink_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = w - Wtar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)w - exactW - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side(SHR_L, marginL);\n            gen_shrink_side(SHR_R, marginR);\n\n            ld exactH = (ld)need / (ld)w;\n            vector<int> htars;\n            add_target_lengths(htars, exactH, h, false);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_shrink_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = h - Htar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)h - exactH - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side_v(SHR_B, marginB);\n            gen_shrink_side_v(SHR_T, marginT);\n        }\n\n        Move best;\n        for (const auto& mv : cands) {\n            if (better_move(mv, best)) best = mv;\n        }\n        return best;\n    }\n\n    vector<int> build_order(const vector<Rect>& rects, int mode, bool reverse_axis) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n\n        if (mode == 0) return ord;\n\n        if (mode == 1) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return rs[a] > rs[b];\n            });\n        } else if (mode == 2) {\n            vector<ld> key(n);\n            for (int i = 0; i < n; ++i) key[i] = 1.0L - satisfaction((ld)rs[i], (ld)rects[i].area());\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        } else if (mode == 3) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] < xs[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] > xs[b];\n                });\n            }\n        } else if (mode == 4) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] < ys[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] > ys[b];\n                });\n            }\n        } else if (mode == 5) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rs[a] - rects[a].area()) > (rs[b] - rects[b].area());\n            });\n        } else if (mode == 6) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rects[a].area() - rs[a]) > (rects[b].area() - rs[b]);\n            });\n        }\n\n        return ord;\n    }\n\n    long long sum_requests(const vector<int>& ids) const {\n        long long s = 0;\n        for (int id : ids) s += rs[id];\n        return s;\n    }\n\n    static ld log_aspect(int w, int h) {\n        ld a = (ld)max(w, h) / (ld)min(w, h);\n        return log(a);\n    }\n\n    vector<SplitCand> generate_bsp_candidates(const vector<int>& ids,\n                                              int lx, int ly, int rx, int ry,\n                                              const BSPParams& par,\n                                              bool optimize_score) {\n        vector<SplitCand> res;\n        int m = (int)ids.size();\n        if (m <= 1) return res;\n\n        int W = rx - lx, H = ry - ly;\n        ld regionArea = (ld)W * (ld)H;\n\n        vector<int> xord = ids, yord = ids;\n        sort(xord.begin(), xord.end(), [&](int a, int b) {\n            if (xs[a] != xs[b]) return xs[a] < xs[b];\n            return ys[a] < ys[b];\n        });\n        sort(yord.begin(), yord.end(), [&](int a, int b) {\n            if (ys[a] != ys[b]) return ys[a] < ys[b];\n            return xs[a] < xs[b];\n        });\n\n        auto make_score = [&](bool vertical, int cut,\n                              const vector<int>& left, const vector<int>& right,\n                              long long reqL, long long reqTot) -> SplitCand {\n            SplitCand c;\n            c.vertical = vertical;\n            c.cut = cut;\n            c.left = left;\n            c.right = right;\n\n            long long reqR = reqTot - reqL;\n\n            ld areaL, areaR;\n            int w1, h1, w2, h2, step;\n            if (vertical) {\n                w1 = cut - lx; h1 = H;\n                w2 = rx - cut; h2 = H;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = H;\n            } else {\n                w1 = W; h1 = cut - ly;\n                w2 = W; h2 = ry - cut;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = W;\n            }\n\n            ld proxy = (ld)left.size() * satisfaction((ld)reqL, areaL)\n                     + (ld)right.size() * satisfaction((ld)reqR, areaR);\n\n            ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n            ld err = fabsl(areaL - scaledL) / regionArea;\n            ld shape = log_aspect(w1, h1) + log_aspect(w2, h2);\n\n            ld score;\n            if (optimize_score) {\n                score = proxy\n                      - par.err_w * err\n                      - par.aspect_w * shape\n                      - par.step_w * ((ld)step / (ld)BOARD);\n\n                if (par.orient_bias == 1 && vertical) score += 1e-3L;\n                if (par.orient_bias == -1 && !vertical) score += 1e-3L;\n                if (par.smart_bias) {\n                    if (W > H && vertical) score += 5e-4L;\n                    if (H > W && !vertical) score += 5e-4L;\n                }\n                score += rng.uniform() * 1e-6L;\n            } else {\n                score = -0.05L * shape - 0.001L * ((ld)step / (ld)BOARD) + rng.uniform() * 1e-6L;\n            }\n            c.score = score;\n            return c;\n        };\n\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[xord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int xL = xs[xord[k - 1]];\n                int xR = xs[xord[k]];\n                int lo = max(lx + 1, xL + 1);\n                int hi = min(rx - 1, xR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, lx + ceil_div_int(k, H));\n                int ahi = min(hi, rx - ceil_div_int(m - k, H));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)lx + scaledL / (ld)H;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    c = max(c, alo);\n                    c = min(c, ahi);\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(xord.begin(), xord.begin() + k);\n                vector<int> right(xord.begin() + k, xord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(true, cut, left, right, reqL, reqTot));\n                }\n            }\n        }\n\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[yord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int yL = ys[yord[k - 1]];\n                int yR = ys[yord[k]];\n                int lo = max(ly + 1, yL + 1);\n                int hi = min(ry - 1, yR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, ly + ceil_div_int(k, W));\n                int ahi = min(hi, ry - ceil_div_int(m - k, W));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)ly + scaledL / (ld)W;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    c = max(c, alo);\n                    c = min(c, ahi);\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(yord.begin(), yord.begin() + k);\n                vector<int> right(yord.begin() + k, yord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(false, cut, left, right, reqL, reqTot));\n                }\n            }\n        }\n\n        sort(res.begin(), res.end(), [&](const SplitCand& a, const SplitCand& b) {\n            return a.score > b.score;\n        });\n        return res;\n    }\n\n    bool partition_rec_simple(const vector<int>& ids,\n                              int lx, int ly, int rx, int ry,\n                              vector<Rect>& out) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        BSPParams dummy;\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, dummy, false);\n        if (cands.empty()) return false;\n\n        for (const auto& c : cands) {\n            if (c.vertical) {\n                if (partition_rec_simple(c.left, lx, ly, c.cut, ry, out) &&\n                    partition_rec_simple(c.right, c.cut, ly, rx, ry, out)) return true;\n            } else {\n                if (partition_rec_simple(c.left, lx, ly, rx, c.cut, out) &&\n                    partition_rec_simple(c.right, lx, c.cut, rx, ry, out)) return true;\n            }\n        }\n        return false;\n    }\n\n    bool partition_rec_opt(const vector<int>& ids,\n                           int lx, int ly, int rx, int ry,\n                           vector<Rect>& out,\n                           const BSPParams& par,\n                           int depth) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, par, true);\n        if (cands.empty()) {\n            return partition_rec_simple(ids, lx, ly, rx, ry, out);\n        }\n\n        int limit = min((int)cands.size(), par.top_try + (depth <= 2 ? 4 : 0));\n        for (int idx = 0; idx < limit; ++idx) {\n            const auto& c = cands[idx];\n            bool ok;\n            if (c.vertical) {\n                ok = partition_rec_opt(c.left, lx, ly, c.cut, ry, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, c.cut, ly, rx, ry, out, par, depth + 1);\n            } else {\n                ok = partition_rec_opt(c.left, lx, ly, rx, c.cut, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, lx, c.cut, rx, ry, out, par, depth + 1);\n            }\n            if (ok) return true;\n        }\n\n        return partition_rec_simple(ids, lx, ly, rx, ry, out);\n    }\n\n    vector<Rect> build_partition_solution(const BSPParams& par) {\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        vector<Rect> rects(n, {0, 0, 0, 0});\n        bool ok = partition_rec_opt(ids, 0, 0, BOARD, BOARD, rects, par, 0);\n        if (!ok) return initial_rects();\n        for (int i = 0; i < n; ++i) {\n            if (!(0 <= rects[i].l && rects[i].l < rects[i].r && rects[i].r <= BOARD &&\n                  0 <= rects[i].b && rects[i].b < rects[i].t && rects[i].t <= BOARD)) {\n                return initial_rects();\n            }\n            if (!(rects[i].l <= xs[i] && xs[i] < rects[i].r &&\n                  rects[i].b <= ys[i] && ys[i] < rects[i].t)) {\n                return initial_rects();\n            }\n        }\n        return rects;\n    }\n\n    ld optimize(vector<Rect>& rects, const Params& params) {\n        long long occ = occupied_area(rects);\n\n        if (occ > 95000000LL) {\n            for (int rep = 0; rep < 2; ++rep) {\n                bool any = false;\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n                if (!any) break;\n            }\n        }\n\n        for (int pass = 0; pass < (int)params.caps.size(); ++pass) {\n            ld cap = params.caps[pass];\n            bool aggressive = (cap > 1e20L);\n            int mode = aggressive ? ((pass & 1) ? 5 : 2) : params.order_mode;\n            vector<int> ord = build_order(rects, mode, params.reverse_axis);\n\n            bool any = false;\n            for (int idx : ord) {\n                Move mv = best_move_for_rect(idx, rects, cap, aggressive,\n                                             params.action_prio, MASK_ALL);\n                if (mv.valid) {\n                    apply_move(rects[idx], mv.action, mv.delta);\n                    any = true;\n                }\n            }\n            if (!any && aggressive) break;\n        }\n\n        for (int rep = 0; rep < 2; ++rep) {\n            bool any = false;\n\n            {\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 5, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_EXP);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 2, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_ALL);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return total_score(rects);\n    }\n\n    array<int, 8> random_action_priority() {\n        vector<int> ord(8);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n        array<int, 8> pr{};\n        for (int i = 0; i < 8; ++i) pr[ord[i]] = i;\n        return pr;\n    }\n\n    Params random_constructive_params() {\n        Params p;\n        ld c0 = 0.85L + 0.40L * rng.uniform();\n        p.caps = {c0, c0 * 1.35L, c0 * 1.8L, c0 * 2.5L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.25L) p.order_mode = 0;\n        else if (u < 0.48L) p.order_mode = 1;\n        else if (u < 0.70L) p.order_mode = 2;\n        else if (u < 0.85L) p.order_mode = 5;\n        else if (u < 0.925L) p.order_mode = 3;\n        else p.order_mode = 4;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_perturb_params() {\n        Params p;\n        ld c0 = 0.95L + 0.55L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, c0 * 2.2L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 2;\n        else if (u < 0.70L) p.order_mode = 5;\n        else if (u < 0.90L) p.order_mode = 6;\n        else p.order_mode = 1;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_partition_params() {\n        Params p;\n        ld c0 = 1.00L + 0.35L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 6;\n        else if (u < 0.75L) p.order_mode = 2;\n        else if (u < 0.92L) p.order_mode = 5;\n        else p.order_mode = 1;\n\n        p.reverse_axis = false;\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params polish_params() {\n        Params p;\n        p.caps = {1.05L, 1.35L, 1.8L, INF_CAP, INF_CAP};\n        p.order_mode = 2;\n        p.reverse_axis = false;\n        for (int i = 0; i < 8; ++i) p.action_prio[i] = i;\n        return p;\n    }\n\n    BSPParams random_bsp_params() {\n        BSPParams p;\n        p.err_w = 0.20L + 0.80L * rng.uniform();\n        p.aspect_w = 0.008L + 0.030L * rng.uniform();\n        p.step_w = 0.000L + 0.030L * rng.uniform();\n        p.orient_bias = rng.next_int(3) - 1;\n        p.top_try = 5 + rng.next_int(6);\n        p.smart_bias = true;\n        return p;\n    }\n\n    int weighted_pick(const vector<ld>& w, const vector<char>& banned) {\n        ld sum = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) sum += w[i];\n        if (sum <= 0) {\n            vector<int> cand;\n            for (int i = 0; i < n; ++i) if (!banned[i]) cand.push_back(i);\n            if (cand.empty()) return -1;\n            return cand[rng.next_int((int)cand.size())];\n        }\n        ld z = rng.uniform() * sum;\n        ld acc = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) {\n            acc += w[i];\n            if (acc >= z) return i;\n        }\n        for (int i = n - 1; i >= 0; --i) if (!banned[i]) return i;\n        return -1;\n    }\n\n    vector<Rect> perturb_from_best(const vector<Rect>& best) {\n        vector<Rect> seed = best;\n        vector<ld> w(n);\n        for (int i = 0; i < n; ++i) {\n            w[i] = 0.01L + (1.0L - satisfaction((ld)rs[i], (ld)best[i].area()));\n        }\n        vector<char> banned(n, 0);\n        int k = 1 + rng.next_int(min(5, n));\n\n        auto reset_rect = [&](int idx) {\n            if (idx < 0) return;\n            seed[idx] = {xs[idx], ys[idx], xs[idx] + 1, ys[idx] + 1};\n            banned[idx] = 1;\n        };\n\n        for (int it = 0; it < k; ++it) {\n            int idx = weighted_pick(w, banned);\n            if (idx < 0) break;\n            reset_rect(idx);\n            if (nearest_idx[idx] != -1 && rng.next_int(100) < 55) {\n                reset_rect(nearest_idx[idx]);\n            }\n        }\n        return seed;\n    }\n\n    static void add_unique_int(vector<int>& v, int x) {\n        v.push_back(x);\n    }\n\n    bool choose_interval_around_anchor(int L, int R, int anchor, int len, int& outL) const {\n        int lo = max(L, anchor - len + 1);\n        int hi = min(anchor, R - len);\n        if (lo > hi) return false;\n        int ideal = anchor - (len - 1) / 2;\n        if (ideal < lo) ideal = lo;\n        if (ideal > hi) ideal = hi;\n        outL = ideal;\n        return true;\n    }\n\n    pair<bool, Rect> best_rebuild_candidate(int i, const vector<Rect>& rects, bool allow_equal) const {\n        const Rect& cur = rects[i];\n        Rect best = cur;\n        ld best_sat = satisfaction((ld)rs[i], (ld)cur.area());\n        ld best_sec = rect_sec_metric(i, cur);\n\n        auto consider = [&](const Rect& nr) {\n            if (!(0 <= nr.l && nr.l < nr.r && nr.r <= BOARD &&\n                  0 <= nr.b && nr.b < nr.t && nr.t <= BOARD)) return;\n            if (!(nr.l <= xs[i] && xs[i] < nr.r && nr.b <= ys[i] && ys[i] < nr.t)) return;\n\n            ld nsat = satisfaction((ld)rs[i], (ld)nr.area());\n            ld nsec = rect_sec_metric(i, nr);\n\n            const ld EPS = 1e-18L;\n            bool better = false;\n            if (nsat > best_sat + EPS) better = true;\n            else if (allow_equal && fabsl(nsat - best_sat) <= EPS && nsec + 1e-15L < best_sec) better = true;\n\n            if (better) {\n                best = nr;\n                best_sat = nsat;\n                best_sec = nsec;\n            }\n        };\n\n        {\n            vector<int> Bs, Ts;\n            Bs.reserve(n + 4);\n            Ts.reserve(n + 4);\n            add_unique_int(Bs, 0);\n            add_unique_int(Bs, cur.b);\n            add_unique_int(Ts, BOARD);\n            add_unique_int(Ts, cur.t);\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.t <= ys[i]) add_unique_int(Bs, o.t);\n                if (o.b >= ys[i] + 1) add_unique_int(Ts, o.b);\n            }\n            sort(Bs.begin(), Bs.end());\n            Bs.erase(unique(Bs.begin(), Bs.end()), Bs.end());\n            sort(Ts.begin(), Ts.end());\n            Ts.erase(unique(Ts.begin(), Ts.end()), Ts.end());\n\n            int curW = cur.r - cur.l;\n            for (int b : Bs) {\n                if (b > ys[i]) continue;\n                for (int t : Ts) {\n                    if (t < ys[i] + 1) continue;\n                    if (b >= t) continue;\n\n                    int L = 0, R = BOARD;\n                    bool valid = true;\n                    for (int j = 0; j < n; ++j) if (j != i) {\n                        const Rect& o = rects[j];\n                        if (!overlap1d(b, t, o.b, o.t)) continue;\n\n                        if (overlap1d(o.l, o.r, xs[i], xs[i] + 1)) {\n                            valid = false;\n                            break;\n                        }\n                        if (o.r <= xs[i]) L = max(L, o.r);\n                        else if (o.l >= xs[i] + 1) R = min(R, o.l);\n                        else {\n                            valid = false;\n                            break;\n                        }\n                    }\n                    if (!valid || L >= R) continue;\n\n                    int h = t - b;\n                    int wcap = R - L;\n                    if (wcap <= 0) continue;\n\n                    vector<int> candW;\n                    auto addW = [&](int W) {\n                        if (1 <= W && W <= wcap) candW.push_back(W);\n                    };\n                    ld tw = (ld)rs[i] / (ld)h;\n                    addW((int)floor(tw + 1e-12L));\n                    addW((int)ceil(tw - 1e-12L));\n                    addW((int)llround(tw));\n                    addW(curW);\n                    addW(wcap);\n                    sort(candW.begin(), candW.end());\n                    candW.erase(unique(candW.begin(), candW.end()), candW.end());\n\n                    for (int W : candW) {\n                        int l;\n                        if (!choose_interval_around_anchor(L, R, xs[i], W, l)) continue;\n                        Rect nr{l, b, l + W, t};\n                        consider(nr);\n                    }\n                }\n            }\n        }\n\n        {\n            vector<int> Ls, Rs;\n            Ls.reserve(n + 4);\n            Rs.reserve(n + 4);\n            add_unique_int(Ls, 0);\n            add_unique_int(Ls, cur.l);\n            add_unique_int(Rs, BOARD);\n            add_unique_int(Rs, cur.r);\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.r <= xs[i]) add_unique_int(Ls, o.r);\n                if (o.l >= xs[i] + 1) add_unique_int(Rs, o.l);\n            }\n            sort(Ls.begin(), Ls.end());\n            Ls.erase(unique(Ls.begin(), Ls.end()), Ls.end());\n            sort(Rs.begin(), Rs.end());\n            Rs.erase(unique(Rs.begin(), Rs.end()), Rs.end());\n\n            int curH = cur.t - cur.b;\n            for (int l : Ls) {\n                if (l > xs[i]) continue;\n                for (int r : Rs) {\n                    if (r < xs[i] + 1) continue;\n                    if (l >= r) continue;\n\n                    int B = 0, T = BOARD;\n                    bool valid = true;\n                    for (int j = 0; j < n; ++j) if (j != i) {\n                        const Rect& o = rects[j];\n                        if (!overlap1d(l, r, o.l, o.r)) continue;\n\n                        if (overlap1d(o.b, o.t, ys[i], ys[i] + 1)) {\n                            valid = false;\n                            break;\n                        }\n                        if (o.t <= ys[i]) B = max(B, o.t);\n                        else if (o.b >= ys[i] + 1) T = min(T, o.b);\n                        else {\n                            valid = false;\n                            break;\n                        }\n                    }\n                    if (!valid || B >= T) continue;\n\n                    int w = r - l;\n                    int hcap = T - B;\n                    if (hcap <= 0) continue;\n\n                    vector<int> candH;\n                    auto addH = [&](int H) {\n                        if (1 <= H && H <= hcap) candH.push_back(H);\n                    };\n                    ld th = (ld)rs[i] / (ld)w;\n                    addH((int)floor(th + 1e-12L));\n                    addH((int)ceil(th - 1e-12L));\n                    addH((int)llround(th));\n                    addH(curH);\n                    addH(hcap);\n                    sort(candH.begin(), candH.end());\n                    candH.erase(unique(candH.begin(), candH.end()), candH.end());\n\n                    for (int H : candH) {\n                        int b;\n                        if (!choose_interval_around_anchor(B, T, ys[i], H, b)) continue;\n                        Rect nr{l, b, r, b + H};\n                        consider(nr);\n                    }\n                }\n            }\n        }\n\n        if (best.l == cur.l && best.b == cur.b && best.r == cur.r && best.t == cur.t) {\n            return {false, cur};\n        }\n        return {true, best};\n    }\n\n    PairCand best_pair_rebuild_candidate(int i, int j, const vector<Rect>& rects, bool allow_equal) const {\n        PairCand res;\n        if (i == j) return res;\n\n        const Rect& a0 = rects[i];\n        const Rect& b0 = rects[j];\n        int L = min(a0.l, b0.l);\n        int B = min(a0.b, b0.b);\n        int R = max(a0.r, b0.r);\n        int T = max(a0.t, b0.t);\n\n        for (int k = 0; k < n; ++k) if (k != i && k != j) {\n            const Rect& o = rects[k];\n            if (overlap1d(L, R, o.l, o.r) && overlap1d(B, T, o.b, o.t)) {\n                return res;\n            }\n        }\n\n        ld cur_sat = satisfaction((ld)rs[i], (ld)a0.area()) + satisfaction((ld)rs[j], (ld)b0.area());\n        ld cur_sec = rect_sec_metric(i, a0) + rect_sec_metric(j, b0);\n\n        ld best_sat = cur_sat;\n        ld best_sec = cur_sec;\n        Rect best_i = a0, best_j = b0;\n\n        auto consider = [&](const Rect& ri, const Rect& rj) {\n            if (!(0 <= ri.l && ri.l < ri.r && ri.r <= BOARD && 0 <= ri.b && ri.b < ri.t && ri.t <= BOARD)) return;\n            if (!(0 <= rj.l && rj.l < rj.r && rj.r <= BOARD && 0 <= rj.b && rj.b < rj.t && rj.t <= BOARD)) return;\n            if (!(ri.l <= xs[i] && xs[i] < ri.r && ri.b <= ys[i] && ys[i] < ri.t)) return;\n            if (!(rj.l <= xs[j] && xs[j] < rj.r && rj.b <= ys[j] && ys[j] < rj.t)) return;\n            if (overlap1d(ri.l, ri.r, rj.l, rj.r) && overlap1d(ri.b, ri.t, rj.b, rj.t)) return;\n\n            ld nsat = satisfaction((ld)rs[i], (ld)ri.area()) + satisfaction((ld)rs[j], (ld)rj.area());\n            ld nsec = rect_sec_metric(i, ri) + rect_sec_metric(j, rj);\n\n            const ld EPS = 1e-18L;\n            bool better = false;\n            if (nsat > best_sat + EPS) better = true;\n            else if (allow_equal && fabsl(nsat - best_sat) <= EPS && nsec + 1e-15L < best_sec) better = true;\n\n            if (better) {\n                best_sat = nsat;\n                best_sec = nsec;\n                best_i = ri;\n                best_j = rj;\n            }\n        };\n\n        auto push_cut = [&](vector<int>& v, int c, int lo, int hi) {\n            if (c < lo) c = lo;\n            if (c > hi) c = hi;\n            v.push_back(c);\n        };\n\n        // Vertical split.\n        if (xs[i] < xs[j]) {\n            int lo = xs[i] + 1;\n            int hi = xs[j];\n            if (lo <= hi) {\n                int H = T - B;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)L + (ld)rs[i] / (ld)H;\n                ld z2 = (ld)R - (ld)rs[j] / (ld)H;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (a0.r == b0.l) push_cut(cuts, a0.r, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, B, c, T}, Rect{c, B, R, T});\n                }\n            }\n        } else if (xs[j] < xs[i]) {\n            int lo = xs[j] + 1;\n            int hi = xs[i];\n            if (lo <= hi) {\n                int H = T - B;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)L + (ld)rs[j] / (ld)H;\n                ld z2 = (ld)R - (ld)rs[i] / (ld)H;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (b0.r == a0.l) push_cut(cuts, b0.r, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{c, B, R, T}, Rect{L, B, c, T});\n                }\n            }\n        }\n\n        // Horizontal split.\n        if (ys[i] < ys[j]) {\n            int lo = ys[i] + 1;\n            int hi = ys[j];\n            if (lo <= hi) {\n                int W = R - L;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)B + (ld)rs[i] / (ld)W;\n                ld z2 = (ld)T - (ld)rs[j] / (ld)W;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (a0.t == b0.b) push_cut(cuts, a0.t, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, B, R, c}, Rect{L, c, R, T});\n                }\n            }\n        } else if (ys[j] < ys[i]) {\n            int lo = ys[j] + 1;\n            int hi = ys[i];\n            if (lo <= hi) {\n                int W = R - L;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)B + (ld)rs[j] / (ld)W;\n                ld z2 = (ld)T - (ld)rs[i] / (ld)W;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (b0.t == a0.b) push_cut(cuts, b0.t, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, c, R, T}, Rect{L, B, R, c});\n                }\n            }\n        }\n\n        const ld EPS = 1e-18L;\n        if (best_sat > cur_sat + EPS || (allow_equal && fabsl(best_sat - cur_sat) <= EPS && best_sec + 1e-15L < cur_sec)) {\n            res.valid = true;\n            res.i = i;\n            res.j = j;\n            res.ri = best_i;\n            res.rj = best_j;\n            res.gain = best_sat - cur_sat;\n            res.sec = best_sec;\n        }\n        return res;\n    }\n\n    bool rebuild_pass(vector<Rect>& rects, int K, bool allow_equal) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        partial_sort(ord.begin(), ord.begin() + min(K, n), ord.end(), [&](int a, int b) {\n            ld da = 1.0L - satisfaction((ld)rs[a], (ld)rects[a].area());\n            ld db = 1.0L - satisfaction((ld)rs[b], (ld)rects[b].area());\n            if (fabsl(da - db) > 1e-18L) return da > db;\n            return rs[a] > rs[b];\n        });\n\n        bool any = false;\n        K = min(K, n);\n        for (int z = 0; z < K; ++z) {\n            int i = ord[z];\n            auto [ok, nr] = best_rebuild_candidate(i, rects, allow_equal);\n            if (ok) {\n                rects[i] = nr;\n                any = true;\n            }\n        }\n        return any;\n    }\n\n    bool pair_rebuild_pass(vector<Rect>& rects, int K, bool allow_equal) {\n        K = min(K, n);\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        partial_sort(ord.begin(), ord.begin() + K, ord.end(), [&](int a, int b) {\n            ld da = 1.0L - satisfaction((ld)rs[a], (ld)rects[a].area());\n            ld db = 1.0L - satisfaction((ld)rs[b], (ld)rects[b].area());\n            if (fabsl(da - db) > 1e-18L) return da > db;\n            return rs[a] > rs[b];\n        });\n\n        vector<char> bad(n, 0);\n        for (int z = 0; z < K; ++z) bad[ord[z]] = 1;\n\n        PairCand best;\n        for (int z = 0; z < K; ++z) {\n            int i = ord[z];\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (bad[j] && j < i) continue;\n                PairCand cand = best_pair_rebuild_candidate(i, j, rects, allow_equal);\n                if (better_pair(cand, best)) best = cand;\n            }\n        }\n\n        if (best.valid) {\n            rects[best.i] = best.ri;\n            rects[best.j] = best.rj;\n            return true;\n        }\n        return false;\n    }\n\n    ld elapsed_sec() const {\n        return chrono::duration<ld>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    void try_update_best(vector<Rect>& cur, ld sc, vector<Rect>& best_rects, ld& best_score) {\n        if (sc > best_score) {\n            best_score = sc;\n            best_rects = cur;\n        }\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        xs.resize(n);\n        ys.resize(n);\n        rs.resize(n);\n        sqrs.resize(n);\n\n        uint64_t seed = 1469598103934665603ULL;\n        for (int i = 0; i < n; ++i) {\n            cin >> xs[i] >> ys[i] >> rs[i];\n            sqrs[i] = sqrt((ld)rs[i]);\n            seed ^= (uint64_t)(xs[i] + 1) * 1000003ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(ys[i] + 7) * 1000033ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(rs[i] + 13) * 1000037ULL;\n            seed *= 1099511628211ULL;\n        }\n        rng = XorShift64(seed);\n\n        nearest_idx.assign(n, -1);\n        for (int i = 0; i < n; ++i) {\n            long long bestd = (1LL << 62);\n            for (int j = 0; j < n; ++j) if (i != j) {\n                long long dx = xs[i] - xs[j];\n                long long dy = ys[i] - ys[j];\n                long long d = dx * dx + dy * dy;\n                if (d < bestd) {\n                    bestd = d;\n                    nearest_idx[i] = j;\n                }\n            }\n        }\n\n        start_time = chrono::steady_clock::now();\n\n        vector<Rect> best_rects = initial_rects();\n        ld best_score = total_score(best_rects);\n\n        for (int t = 0; t < 2 && elapsed_sec() < 1.35L; ++t) {\n            vector<Rect> cur = initial_rects();\n            Params p = random_constructive_params();\n            ld sc = optimize(cur, p);\n            try_update_best(cur, sc, best_rects, best_score);\n        }\n\n        for (int t = 0; t < 4 && elapsed_sec() < 2.30L; ++t) {\n            vector<Rect> cur = build_partition_solution(random_bsp_params());\n            Params p = random_partition_params();\n            ld sc = optimize(cur, p);\n            try_update_best(cur, sc, best_rects, best_score);\n        }\n\n        int iter = 0;\n        while (elapsed_sec() < 4.50L) {\n            vector<Rect> cur;\n            Params p;\n\n            if (iter < 6) {\n                if (iter & 1) {\n                    cur = build_partition_solution(random_bsp_params());\n                    p = random_partition_params();\n                } else {\n                    cur = initial_rects();\n                    p = random_constructive_params();\n                }\n            } else {\n                ld u = rng.uniform();\n                if (u < 0.18L) {\n                    cur = initial_rects();\n                    p = random_constructive_params();\n                } else if (u < 0.42L) {\n                    cur = build_partition_solution(random_bsp_params());\n                    p = random_partition_params();\n                } else {\n                    cur = perturb_from_best(best_rects);\n                    p = random_perturb_params();\n                }\n            }\n\n            ld sc = optimize(cur, p);\n\n            if (sc > best_score) {\n                best_score = sc;\n                best_rects = cur;\n\n                if (elapsed_sec() < 4.24L) {\n                    vector<Rect> tmp = best_rects;\n                    bool any = false;\n                    any |= pair_rebuild_pass(tmp, min(10, n), true);\n                    any |= rebuild_pass(tmp, min(6, n), true);\n                    if (any) {\n                        ld sc2 = optimize(tmp, polish_params());\n                        if (sc2 > best_score) {\n                            best_score = sc2;\n                            best_rects = move(tmp);\n                        }\n                    }\n                }\n            }\n\n            ++iter;\n        }\n\n        while (elapsed_sec() < 4.92L) {\n            bool any = false;\n            any |= pair_rebuild_pass(best_rects, min(12, n), true);\n            if (elapsed_sec() >= 4.92L) break;\n            any |= pair_rebuild_pass(best_rects, min(12, n), true);\n            if (elapsed_sec() >= 4.92L) break;\n            any |= rebuild_pass(best_rects, min(10, n), true);\n            if (!any) break;\n\n            ld old = best_score;\n            ld sc = optimize(best_rects, polish_params());\n            if (sc > best_score) best_score = sc;\n            if (sc <= old + 1e-18L) break;\n        }\n\n        for (int i = 0; i < n; ++i) {\n            cout << best_rects[i].l << ' ' << best_rects[i].b << ' '\n                 << best_rects[i].r << ' ' << best_rects[i].t << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50;\nstatic constexpr int W = 50;\nstatic constexpr int V = H * W;\n\nusing Clock = chrono::steady_clock;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463325252ull;\n    void seed(uint64_t s) { x = s ? s : 88172645463325252ull; }\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\ninline int id(int i, int j) { return i * W + j; }\n\nstruct CompStat {\n    int tiles;\n    int ub;\n};\n\nstruct Params {\n    int lookDepth = 6;\n    int tilesMargin = 0;\n    int ubMargin = 0;\n    int lookMargin = 0;\n    bool deterministic = false;\n};\n\nstruct Path {\n    vector<int> pos;\n    vector<int> prefixScore;\n    vector<unsigned char> branchCnt;\n    vector<int> branchPoints;\n    int score = 0;\n};\n\nstruct MoveInfo {\n    int v = -1;\n    int addScore = 0;\n    int addLen = 0;\n    int reachTiles = 0;\n    int reachUb = 0;\n    int deg = 0;\n    int look = INT_MIN;\n};\n\nint si, sj, startIdx;\nint tileId[V];\nint pval[V];\nint M;\n\nint adjList[V][4];\nunsigned char adjCnt[V];\n\nvector<int> tileMaxVal;\nvector<unsigned char> usedTile;\nvector<unsigned char> tmpUsed;\n\nint visSq[V];\nvector<int> visTile;\nint bfsStamp = 1;\nint tileStamp = 1;\nint qbuf[V];\n\nClock::time_point globalDeadline;\n\n// opening search\nvector<int> openingCur, openingBest;\nlong long openingBestUB = -1;\nint openingBestTiles = -1;\nint openingBestAcc = -1;\nClock::time_point openingDeadline;\nbool openingTimeout = false;\nint openingNodes = 0;\n\ninline int avail_neighbors(int u, int out[4]) {\n    int c = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) out[c++] = v;\n    }\n    return c;\n}\n\ninline CompStat component_stat(int s) {\n    const int st = tileId[s];\n    ++bfsStamp;\n    ++tileStamp;\n\n    int head = 0, tail = 0;\n    qbuf[tail++] = s;\n    visSq[s] = bfsStamp;\n    visTile[st] = tileStamp;\n\n    int tiles = 1;\n    int ub = pval[s];\n\n    while (head < tail) {\n        int u = qbuf[head++];\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            int tv = tileId[v];\n            if (tv == st || usedTile[tv]) continue;\n            if (visSq[v] != bfsStamp) {\n                visSq[v] = bfsStamp;\n                qbuf[tail++] = v;\n            }\n            if (visTile[tv] != tileStamp) {\n                visTile[tv] = tileStamp;\n                ++tiles;\n                ub += tileMaxVal[tv];\n            }\n        }\n    }\n    return {tiles, ub};\n}\n\ninline void best_future_from_current(int u, int& bestTiles, int& bestUb) {\n    bestTiles = 0;\n    bestUb = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (usedTile[tileId[v]]) continue;\n        auto cs = component_stat(v);\n        if (cs.tiles > bestTiles) bestTiles = cs.tiles;\n        if (cs.ub > bestUb) bestUb = cs.ub;\n    }\n}\n\nint local_dfs(int u, int depth) {\n    int trail[16];\n    int tcnt = 0;\n    int gain = 0;\n\n    while (depth > 0) {\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n        if (ccnt == 0) {\n            for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n            return gain;\n        }\n        if (ccnt == 1) {\n            int v = cand[0];\n            int tv = tileId[v];\n            usedTile[tv] = 1;\n            trail[tcnt++] = tv;\n            gain += pval[v];\n            u = v;\n            --depth;\n            continue;\n        }\n        break;\n    }\n\n    if (depth == 0) {\n        for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n        return gain;\n    }\n\n    struct Cand {\n        int v;\n        int pri;\n    };\n    Cand cand2[4];\n    int n2 = 0;\n\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        int tv = tileId[v];\n        if (usedTile[tv]) continue;\n        usedTile[tv] = 1;\n        int out[4];\n        int deg = avail_neighbors(v, out);\n        usedTile[tv] = 0;\n        cand2[n2++] = {v, pval[v] * 8 + deg * 5};\n    }\n\n    sort(cand2, cand2 + n2, [](const Cand& a, const Cand& b) {\n        return a.pri > b.pri;\n    });\n\n    int best = 0;\n    for (int i = 0; i < n2; ++i) {\n        int v = cand2[i].v;\n        int tv = tileId[v];\n        usedTile[tv] = 1;\n        int sc = pval[v] + local_dfs(v, depth - 1);\n        usedTile[tv] = 0;\n        if (sc > best) best = sc;\n    }\n\n    for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n    return gain + best;\n}\n\nvoid preview_move_corridor(int v, MoveInfo& info) {\n    info.v = v;\n\n    int trail[V];\n    int tcnt = 0;\n    int cur = v;\n    int addScore = 0;\n    int addLen = 0;\n\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        trail[tcnt++] = tv;\n        addScore += pval[cur];\n        ++addLen;\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) {\n            int bestTiles = 0, bestUb = 0;\n            for (int i = 0; i < ccnt; ++i) {\n                auto cs = component_stat(cand[i]);\n                if (cs.tiles > bestTiles) bestTiles = cs.tiles;\n                if (cs.ub > bestUb) bestUb = cs.ub;\n            }\n            info.addScore = addScore;\n            info.addLen = addLen;\n            info.deg = ccnt;\n            info.reachTiles = addLen + bestTiles;\n            info.reachUb = addScore + bestUb;\n            break;\n        }\n        cur = cand[0];\n    }\n\n    for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n}\n\nint look_move_corridor(int v, int totalDepth) {\n    int trail[V];\n    int tcnt = 0;\n    int cur = v;\n    int addScore = 0;\n    int addLen = 0;\n\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        trail[tcnt++] = tv;\n        addScore += pval[cur];\n        ++addLen;\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) {\n            int rem = max(0, totalDepth - addLen);\n            int res = addScore + local_dfs(cur, rem);\n            for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n            return res;\n        }\n        cur = cand[0];\n    }\n}\n\nvoid commit_corridor(Path& res, int v) {\n    int cur = v;\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        res.pos.push_back(cur);\n        res.score += pval[cur];\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) break;\n        cur = cand[0];\n    }\n}\n\nbool better_move(const MoveInfo& a, const MoveInfo& b, int step, bool deterministic) {\n    if (deterministic || step < 80) {\n        if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n        if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n        if (a.look != b.look) return a.look > b.look;\n    } else if (step < 250) {\n        if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n        if (a.look != b.look) return a.look > b.look;\n        if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n    } else {\n        if (a.look != b.look) return a.look > b.look;\n        if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n        if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n    }\n    if (a.addScore != b.addScore) return a.addScore > b.addScore;\n    if (a.deg != b.deg) return a.deg > b.deg;\n    return pval[a.v] > pval[b.v];\n}\n\nPath build_path(vector<int> pos, int score, const Params& prm, const Clock::time_point& deadline) {\n    Path res;\n    res.pos = std::move(pos);\n    res.score = score;\n    res.pos.reserve(V);\n\n    int it = 0;\n    while (true) {\n        if ((it++ & 31) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n\n        int u = res.pos.back();\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n        if (ccnt == 0) break;\n\n        if (ccnt == 1) {\n            commit_corridor(res, cand[0]);\n            continue;\n        }\n\n        MoveInfo info[4];\n        for (int i = 0; i < ccnt; ++i) preview_move_corridor(cand[i], info[i]);\n\n        int step = (int)res.pos.size();\n        int baseTM, baseUM, baseLM;\n        if (prm.deterministic || step < 60) {\n            baseTM = 0; baseUM = 40; baseLM = 4;\n        } else if (step < 180) {\n            baseTM = 1; baseUM = 120; baseLM = 8;\n        } else if (step < 400) {\n            baseTM = 2; baseUM = 220; baseLM = 12;\n        } else {\n            baseTM = 4; baseUM = 450; baseLM = 18;\n        }\n        int tm = baseTM + prm.tilesMargin;\n        int um = baseUM + prm.ubMargin;\n        int lm = baseLM + prm.lookMargin;\n\n        int lookDepth = prm.lookDepth + (step < 30 ? 2 : step < 90 ? 1 : 0);\n        if (prm.deterministic) ++lookDepth;\n        lookDepth = min(lookDepth, 10);\n\n        int chosen = info[0].v;\n\n        if (prm.deterministic || step < 30) {\n            for (int i = 0; i < ccnt; ++i) info[i].look = look_move_corridor(info[i].v, lookDepth);\n            int bestIdx = 0;\n            for (int i = 1; i < ccnt; ++i) {\n                if (better_move(info[i], info[bestIdx], step, prm.deterministic)) bestIdx = i;\n            }\n            chosen = info[bestIdx].v;\n        } else {\n            int alive[4];\n            int acnt = ccnt;\n            for (int i = 0; i < ccnt; ++i) alive[i] = i;\n\n            int bestTiles = -1;\n            for (int i = 0; i < acnt; ++i) bestTiles = max(bestTiles, info[alive[i]].reachTiles);\n            {\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].reachTiles >= bestTiles - tm) nxt[ncnt++] = idx;\n                }\n                for (int i = 0; i < ncnt; ++i) alive[i] = nxt[i];\n                acnt = ncnt;\n            }\n\n            int bestUb = -1;\n            for (int i = 0; i < acnt; ++i) bestUb = max(bestUb, info[alive[i]].reachUb);\n            {\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].reachUb >= bestUb - um) nxt[ncnt++] = idx;\n                }\n                for (int i = 0; i < ncnt; ++i) alive[i] = nxt[i];\n                acnt = ncnt;\n            }\n\n            for (int i = 0; i < acnt; ++i) {\n                int idx = alive[i];\n                info[idx].look = look_move_corridor(info[idx].v, lookDepth);\n            }\n\n            int bestLook = INT_MIN;\n            for (int i = 0; i < acnt; ++i) bestLook = max(bestLook, info[alive[i]].look);\n\n            int fin[4], fcnt = 0;\n            int w[4], wsum = 0;\n            for (int i = 0; i < acnt; ++i) {\n                int idx = alive[i];\n                if (info[idx].look >= bestLook - lm) {\n                    fin[fcnt] = idx;\n                    int ww = info[idx].look - (bestLook - lm) + 1;\n                    ww += info[idx].deg * 2;\n                    ww += info[idx].addScore / 12;\n                    if (ww < 1) ww = 1;\n                    w[fcnt] = ww;\n                    wsum += ww;\n                    ++fcnt;\n                }\n            }\n\n            int r = rng.next_int(1, wsum);\n            chosen = info[fin[0]].v;\n            for (int i = 0; i < fcnt; ++i) {\n                r -= w[i];\n                if (r <= 0) {\n                    chosen = info[fin[i]].v;\n                    break;\n                }\n            }\n        }\n\n        commit_corridor(res, chosen);\n    }\n\n    return res;\n}\n\nvoid prepare_path(Path& path) {\n    int n = (int)path.pos.size();\n    path.prefixScore.assign(n, 0);\n    path.branchCnt.assign(n, 0);\n    path.branchPoints.clear();\n\n    fill(tmpUsed.begin(), tmpUsed.end(), 0);\n    int s = 0;\n    for (int i = 0; i < n; ++i) {\n        int u = path.pos[i];\n        tmpUsed[tileId[u]] = 1;\n        s += pval[u];\n        path.prefixScore[i] = s;\n\n        int cnt = 0;\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            if (!tmpUsed[tileId[v]]) ++cnt;\n        }\n        path.branchCnt[i] = (unsigned char)cnt;\n        if (cnt >= 2) path.branchPoints.push_back(i);\n    }\n    path.score = s;\n}\n\nbool better_path(const Path& a, const Path& b) {\n    if (a.score != b.score) return a.score > b.score;\n    return a.pos.size() > b.pos.size();\n}\n\nvoid add_elite(vector<Path>& elites, Path cand, int keep = 6) {\n    prepare_path(cand);\n    elites.push_back(std::move(cand));\n    sort(elites.begin(), elites.end(), [](const Path& a, const Path& b) {\n        return better_path(a, b);\n    });\n    if ((int)elites.size() > keep) elites.resize(keep);\n}\n\nint choose_elite(const vector<Path>& elites) {\n    int n = (int)elites.size();\n    int sum = 0;\n    for (int i = 0; i < n; ++i) sum += (n - i);\n    int r = rng.next_int(1, sum);\n    for (int i = 0; i < n; ++i) {\n        r -= (n - i);\n        if (r <= 0) return i;\n    }\n    return 0;\n}\n\nint choose_cut(const Path& path) {\n    if (path.branchPoints.empty()) return 0;\n    const auto& bp = path.branchPoints;\n    int n = (int)bp.size();\n\n    int l = 0, r = n - 1;\n    if (n >= 3) {\n        int a = n / 3;\n        int b = (2 * n) / 3;\n        double x = rng.next_double();\n        if (x < 0.20) {\n            l = 0; r = max(0, a - 1);\n        } else if (x < 0.60) {\n            l = a; r = max(a, b - 1);\n        } else {\n            l = b; r = n - 1;\n        }\n    }\n    return bp[l + rng.next_int(0, r - l)];\n}\n\n// -------- opening search (branch-point based) --------\n\nvoid consider_open_leaf(int u, int accScore) {\n    int bt, bu;\n    best_future_from_current(u, bt, bu);\n    long long totalUB = (long long)accScore + bu;\n    int totalTiles = (int)openingCur.size() + bt;\n    if (totalUB > openingBestUB ||\n        (totalUB == openingBestUB && (totalTiles > openingBestTiles ||\n         (totalTiles == openingBestTiles && accScore > openingBestAcc)))) {\n        openingBestUB = totalUB;\n        openingBestTiles = totalTiles;\n        openingBestAcc = accScore;\n        openingBest = openingCur;\n    }\n}\n\nvoid opening_dfs(int u, int depthChoices, int accScore) {\n    if (openingTimeout) return;\n    if ((++openingNodes & 511) == 0) {\n        if (Clock::now() >= openingDeadline) {\n            openingTimeout = true;\n            return;\n        }\n    }\n\n    while (true) {\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n\n        if (ccnt == 0) {\n            consider_open_leaf(u, accScore);\n            return;\n        }\n\n        if (ccnt == 1) {\n            int v = cand[0];\n            usedTile[tileId[v]] = 1;\n            openingCur.push_back(v);\n            accScore += pval[v];\n            u = v;\n            continue;\n        }\n\n        int bt, bu;\n        best_future_from_current(u, bt, bu);\n        long long ubTotal = (long long)accScore + bu;\n        int tilesTotal = (int)openingCur.size() + bt;\n        if (ubTotal < openingBestUB ||\n            (ubTotal == openingBestUB && tilesTotal <= openingBestTiles)) {\n            return;\n        }\n\n        if (depthChoices == 0) {\n            consider_open_leaf(u, accScore);\n            return;\n        }\n\n        struct Ord {\n            int v;\n            int reachUb;\n            int reachTiles;\n            int addScore;\n        };\n        Ord ord[4];\n        for (int i = 0; i < ccnt; ++i) {\n            MoveInfo mi;\n            preview_move_corridor(cand[i], mi);\n            ord[i] = {cand[i], mi.reachUb, mi.reachTiles, mi.addScore};\n        }\n\n        sort(ord, ord + ccnt, [](const Ord& a, const Ord& b) {\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            return a.addScore > b.addScore;\n        });\n\n        for (int i = 0; i < ccnt; ++i) {\n            int trail[V];\n            int tcnt = 0;\n            int cur = ord[i].v;\n            int add = 0;\n\n            while (true) {\n                int tv = tileId[cur];\n                usedTile[tv] = 1;\n                trail[tcnt++] = cur;\n                openingCur.push_back(cur);\n                add += pval[cur];\n\n                int nexts[4];\n                int nc = avail_neighbors(cur, nexts);\n                if (nc != 1) break;\n                cur = nexts[0];\n            }\n\n            opening_dfs(cur, depthChoices - 1, accScore + add);\n\n            for (int j = 0; j < tcnt; ++j) usedTile[tileId[trail[j]]] = 0;\n            for (int j = 0; j < tcnt; ++j) openingCur.pop_back();\n\n            if (openingTimeout) return;\n        }\n        return;\n    }\n}\n\nstring to_answer(const vector<int>& pos) {\n    string ans;\n    ans.reserve(pos.size() > 0 ? pos.size() - 1 : 0);\n    for (size_t i = 1; i < pos.size(); ++i) {\n        int d = pos[i] - pos[i - 1];\n        if (d == -W) ans.push_back('U');\n        else if (d == W) ans.push_back('D');\n        else if (d == -1) ans.push_back('L');\n        else if (d == 1) ans.push_back('R');\n    }\n    return ans;\n}\n\nParams random_params(int mode) {\n    Params p;\n    if (mode == 2) { // elite suffix\n        p.lookDepth = 6 + rng.next_int(0, 1);\n        p.tilesMargin = rng.next_int(0, 2);\n        p.ubMargin = rng.next_int(0, 100);\n        p.lookMargin = rng.next_int(0, 8);\n    } else { // restart\n        p.lookDepth = 7 + rng.next_int(0, 1);\n        p.tilesMargin = rng.next_int(0, 1);\n        p.ubMargin = rng.next_int(0, 80);\n        p.lookMargin = rng.next_int(0, 6);\n    }\n    p.deterministic = false;\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj;\n    startIdx = id(si, sj);\n\n    int maxTile = -1;\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int t;\n            cin >> t;\n            tileId[id(i, j)] = t;\n            maxTile = max(maxTile, t);\n        }\n    }\n    M = maxTile + 1;\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            cin >> pval[id(i, j)];\n        }\n    }\n\n    tileMaxVal.assign(M, 0);\n    for (int v = 0; v < V; ++v) {\n        tileMaxVal[tileId[v]] = max(tileMaxVal[tileId[v]], pval[v]);\n    }\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int u = id(i, j);\n            int cnt = 0;\n            const int di[4] = {-1, 1, 0, 0};\n            const int dj[4] = {0, 0, -1, 1};\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 >= H || nj < 0 || nj >= W) continue;\n                int v = id(ni, nj);\n                if (tileId[v] == tileId[u]) continue;\n                adjList[u][cnt++] = v;\n            }\n            adjCnt[u] = (unsigned char)cnt;\n        }\n    }\n\n    usedTile.assign(M, 0);\n    tmpUsed.assign(M, 0);\n    visTile.assign(M, 0);\n    memset(visSq, 0, sizeof(visSq));\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)startIdx + 0x9e3779b97f4a7c15ull;\n    for (int v = 0; v < V; ++v) {\n        seed = seed * 1000003ull ^ (uint64_t)(tileId[v] + 1);\n        seed = seed * 1000003ull ^ (uint64_t)(pval[v] + 7);\n    }\n    rng.seed(seed);\n\n    globalDeadline = Clock::now() + chrono::milliseconds(1950);\n\n    // opening search\n    fill(usedTile.begin(), usedTile.end(), 0);\n    usedTile[tileId[startIdx]] = 1;\n\n    openingCur.clear();\n    openingBest.clear();\n    openingBestUB = -1;\n    openingBestTiles = -1;\n    openingBestAcc = -1;\n    openingTimeout = false;\n    openingNodes = 0;\n    openingDeadline = min(globalDeadline, Clock::now() + chrono::milliseconds(260));\n\n    opening_dfs(startIdx, 9, pval[startIdx]);\n\n    vector<int> openingPrefix;\n    openingPrefix.push_back(startIdx);\n    for (int v : openingBest) openingPrefix.push_back(v);\n\n    vector<Path> elites;\n\n    // baseline 1: opening prefix + deterministic\n    {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        int score = 0;\n        for (int v : openingPrefix) {\n            usedTile[tileId[v]] = 1;\n            score += pval[v];\n        }\n        Params safe;\n        safe.lookDepth = 8;\n        safe.tilesMargin = 0;\n        safe.ubMargin = 0;\n        safe.lookMargin = 0;\n        safe.deterministic = true;\n        Path base = build_path(openingPrefix, score, safe, globalDeadline);\n        add_elite(elites, std::move(base));\n    }\n\n    // baseline 2: start only + deterministic\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        Params safe;\n        safe.lookDepth = 8;\n        safe.deterministic = true;\n        Path base2 = build_path(vector<int>{startIdx}, pval[startIdx], safe, globalDeadline);\n        add_elite(elites, std::move(base2));\n    }\n\n    // baseline 3: opening prefix + randomized\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        int score = 0;\n        for (int v : openingPrefix) {\n            usedTile[tileId[v]] = 1;\n            score += pval[v];\n        }\n        Params rp = random_params(1);\n        Path base3 = build_path(openingPrefix, score, rp, globalDeadline);\n        add_elite(elites, std::move(base3));\n    }\n\n    // iterative improvement\n    while (Clock::now() < globalDeadline) {\n        int mode = 2; // 0:start, 1:opening prefix, 2:elite suffix\n        double x = rng.next_double();\n        if (elites.empty() || x < 0.18) mode = 0;\n        else if (x < 0.40 && openingPrefix.size() > 1) mode = 1;\n\n        fill(usedTile.begin(), usedTile.end(), 0);\n        vector<int> pref;\n        int score = 0;\n\n        if (mode == 0) {\n            pref = {startIdx};\n            usedTile[tileId[startIdx]] = 1;\n            score = pval[startIdx];\n        } else if (mode == 1) {\n            int n = (int)openingPrefix.size();\n            int len;\n            if (n <= 2) len = n;\n            else if (rng.next_double() < 0.55) len = n;\n            else len = rng.next_int(max(1, n / 2), n);\n            pref.assign(openingPrefix.begin(), openingPrefix.begin() + len);\n            for (int v : pref) {\n                usedTile[tileId[v]] = 1;\n                score += pval[v];\n            }\n        } else {\n            int ei = choose_elite(elites);\n            const Path& src = elites[ei];\n            if (src.branchPoints.empty()) {\n                pref = {startIdx};\n                usedTile[tileId[startIdx]] = 1;\n                score = pval[startIdx];\n                mode = 0;\n            } else {\n                int cut = choose_cut(src);\n                pref.assign(src.pos.begin(), src.pos.begin() + cut + 1);\n                score = src.prefixScore[cut];\n                for (int i = 0; i <= cut; ++i) usedTile[tileId[src.pos[i]]] = 1;\n            }\n        }\n\n        Params prm = random_params(mode);\n        Path cand = build_path(std::move(pref), score, prm, globalDeadline);\n        add_elite(elites, std::move(cand));\n    }\n\n    if (elites.empty()) {\n        cout << '\\n';\n        return 0;\n    }\n\n    cout << to_answer(elites[0].pos) << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int HN = N * (N - 1);   // 870\nstatic constexpr int VN = (N - 1) * N;   // 870\nstatic constexpr int E = HN + VN;        // 1740\n\nstatic constexpr double INIT_COST = 5000.0;\nstatic constexpr double MIN_COST = 1000.0;\nstatic constexpr double MAX_COST = 9000.0;\n\ninline int hid(int i, int j) { return i * 29 + j; }          // (i,j) <-> (i,j+1)\ninline int vid(int i, int j) { return HN + i * 30 + j; }     // (i,j) <-> (i+1,j)\ninline int node_id(int i, int j) { return i * N + j; }\n\nstruct Path {\n    string s;\n    vector<int> edges;\n    double sumX = 0.0;\n    double sumPrior = 0.0;\n    double sumUnc = 0.0; // sum 1/sqrt(vis+1)\n};\n\nstruct Observation {\n    vector<int> edges;\n    array<uint8_t, 30> hcnt{};   // # horizontal edges used on each row\n    array<uint8_t, 30> vcnt{};   // # vertical edges used on each column\n    double y = 0.0;\n    double w = 0.0;\n    int len = 0;\n};\n\nstruct FitRes29 {\n    array<double, 29> out{};\n    bool use_two = false;\n    double improve = 0.0;\n    double diff = 0.0;\n};\n\nstruct Solver {\n    vector<double> x;       // current edge estimate\n    vector<double> prior;   // structured prior\n    vector<int> vis;\n    vector<Observation> hist;\n\n    array<double, 30> rowAvgH{};\n    array<double, 30> colAvgV{};\n\n    mt19937 rng;\n\n    Solver() : x(E, INIT_COST), prior(E, INIT_COST), vis(E, 0) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        for (int i = 0; i < 30; ++i) {\n            rowAvgH[i] = INIT_COST;\n            colAvgV[i] = INIT_COST;\n        }\n        hist.reserve(1000);\n    }\n\n    int randint(int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    static double clampd(double x, double lo, double hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    static double dot_vec(const vector<double>& a, const vector<double>& b) {\n        double s = 0.0;\n        for (int i = 0; i < (int)a.size(); ++i) s += a[i] * b[i];\n        return s;\n    }\n\n    inline double est_edge(int e) const {\n        return clampd(x[e], MIN_COST, MAX_COST);\n    }\n\n    inline double plan_edge(int e) const {\n        double conf = (double)vis[e] / ((double)vis[e] + 3.0);\n        return clampd((1.0 - conf) * prior[e] + conf * x[e], MIN_COST, MAX_COST);\n    }\n\n    inline double unc_edge(int e) const {\n        return 1.0 / sqrt((double)vis[e] + 1.0);\n    }\n\n    void finalize_path(Path& p) const {\n        p.sumX = p.sumPrior = p.sumUnc = 0.0;\n        for (int e : p.edges) {\n            p.sumX += est_edge(e);\n            p.sumPrior += prior[e];\n            p.sumUnc += unc_edge(e);\n        }\n    }\n\n    FitRes29 fit_piecewise_29(const array<double, 29>& val, const array<double, 29>& wt) const {\n        FitRes29 res;\n\n        array<double, 30> W{}, S{}, Q{};\n        for (int i = 0; i < 29; ++i) {\n            W[i + 1] = W[i] + wt[i];\n            S[i + 1] = S[i] + wt[i] * val[i];\n            Q[i + 1] = Q[i] + wt[i] * val[i] * val[i];\n        }\n\n        auto seg = [&](int l, int r) -> tuple<double, double, double> {\n            double w = W[r + 1] - W[l];\n            double s = S[r + 1] - S[l];\n            double q = Q[r + 1] - Q[l];\n            if (w < 1e-12) return {INIT_COST, 0.0, 0.0};\n            double m = s / w;\n            double err = q - s * s / w;\n            return {m, err, w};\n        };\n\n        auto [m1, e1, w1] = seg(0, 28);\n\n        double best2 = 1e100;\n        int bestk = -1;\n        double ml = m1, mr = m1;\n        for (int k = 1; k <= 28; ++k) {\n            auto [a, ea, wa] = seg(0, k - 1);\n            auto [b, eb, wb] = seg(k, 28);\n            double tot = ea + eb;\n            if (tot < best2) {\n                best2 = tot;\n                bestk = k;\n                ml = a;\n                mr = b;\n            }\n        }\n\n        res.diff = fabs(ml - mr);\n        if (e1 > 1e-9) res.improve = 1.0 - best2 / e1;\n        else res.improve = 0.0;\n\n        bool two = false;\n        if (bestk != -1 && e1 > 1e-9) {\n            if (best2 < e1 * 0.80 && fabs(ml - mr) > 220.0) {\n                two = true;\n            }\n        }\n        res.use_two = two;\n\n        if (!two) {\n            for (int i = 0; i < 29; ++i) res.out[i] = m1;\n        } else {\n            for (int i = 0; i < bestk; ++i) res.out[i] = ml;\n            for (int i = bestk; i < 29; ++i) res.out[i] = mr;\n        }\n\n        for (int i = 0; i < 29; ++i) {\n            res.out[i] = clampd(res.out[i], MIN_COST, MAX_COST);\n        }\n        return res;\n    }\n\n    Observation make_observation(const Path& path, double y) {\n        Observation ob;\n        ob.edges = path.edges;\n        ob.len = (int)path.edges.size();\n        ob.y = y;\n        ob.w = 1.0 / max(1, ob.len);\n\n        for (int e : path.edges) {\n            if (e < HN) {\n                int r = e / 29;\n                ob.hcnt[r]++;\n            } else {\n                int id = e - HN;\n                int c = id % 30;\n                ob.vcnt[c]++;\n            }\n        }\n        return ob;\n    }\n\n    void solve_coarse_model() {\n        if (hist.empty()) {\n            for (int i = 0; i < 30; ++i) {\n                rowAvgH[i] = INIT_COST;\n                colAvgV[i] = INIT_COST;\n            }\n            return;\n        }\n\n        static double A[60][61];\n        for (int i = 0; i < 60; ++i) {\n            for (int j = 0; j <= 60; ++j) A[i][j] = 0.0;\n        }\n\n        int nobs = (int)hist.size();\n        double lambda = 1.2 / sqrt((double)nobs + 1.0) + 0.12;\n\n        for (int p = 0; p < 60; ++p) {\n            A[p][p] += lambda;\n            A[p][60] += lambda * INIT_COST;\n        }\n\n        vector<pair<int, double>> feats;\n        feats.reserve(60);\n\n        for (const auto& ob : hist) {\n            feats.clear();\n            for (int r = 0; r < 30; ++r) if (ob.hcnt[r]) feats.push_back({r, (double)ob.hcnt[r]});\n            for (int c = 0; c < 30; ++c) if (ob.vcnt[c]) feats.push_back({30 + c, (double)ob.vcnt[c]});\n\n            double w = ob.w;\n            for (auto [i, vi] : feats) {\n                A[i][60] += w * vi * ob.y;\n            }\n            for (auto [i, vi] : feats) {\n                for (auto [j, vj] : feats) {\n                    A[i][j] += w * vi * vj;\n                }\n            }\n        }\n\n        for (int col = 0; col < 60; ++col) {\n            int pivot = col;\n            for (int r = col + 1; r < 60; ++r) {\n                if (fabs(A[r][col]) > fabs(A[pivot][col])) pivot = r;\n            }\n            if (fabs(A[pivot][col]) < 1e-12) continue;\n\n            if (pivot != col) {\n                for (int j = col; j <= 60; ++j) swap(A[pivot][j], A[col][j]);\n            }\n\n            double div = A[col][col];\n            for (int j = col; j <= 60; ++j) A[col][j] /= div;\n\n            for (int r = 0; r < 60; ++r) {\n                if (r == col) continue;\n                double fac = A[r][col];\n                if (fabs(fac) < 1e-12) continue;\n                for (int j = col; j <= 60; ++j) {\n                    A[r][j] -= fac * A[col][j];\n                }\n            }\n        }\n\n        for (int r = 0; r < 30; ++r) rowAvgH[r] = clampd(A[r][60], MIN_COST, MAX_COST);\n        for (int c = 0; c < 30; ++c) colAvgV[c] = clampd(A[30 + c][60], MIN_COST, MAX_COST);\n    }\n\n    void build_prior() {\n        solve_coarse_model();\n\n        for (int i = 0; i < 30; ++i) {\n            for (int j = 0; j < 29; ++j) prior[hid(i, j)] = rowAvgH[i];\n        }\n        for (int j = 0; j < 30; ++j) {\n            for (int i = 0; i < 29; ++i) prior[vid(i, j)] = colAvgV[j];\n        }\n\n        for (int i = 0; i < 30; ++i) {\n            int sumv = 0;\n            array<double, 29> val{}, wt{};\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                val[j] = x[e];\n                wt[j] = vis[e] + 2.0;\n                sumv += vis[e];\n            }\n            if (sumv < 12) continue;\n\n            auto fr = fit_piecewise_29(val, wt);\n            if (!fr.use_two || fr.improve < 0.20) continue;\n\n            double beta = 0.15 + 0.25 * ((double)sumv / ((double)sumv + 20.0));\n            beta = min(beta, 0.40);\n\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                prior[e] = clampd((1.0 - beta) * prior[e] + beta * fr.out[j], MIN_COST, MAX_COST);\n            }\n        }\n\n        for (int j = 0; j < 30; ++j) {\n            int sumv = 0;\n            array<double, 29> val{}, wt{};\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                val[i] = x[e];\n                wt[i] = vis[e] + 2.0;\n                sumv += vis[e];\n            }\n            if (sumv < 12) continue;\n\n            auto fr = fit_piecewise_29(val, wt);\n            if (!fr.use_two || fr.improve < 0.20) continue;\n\n            double beta = 0.15 + 0.25 * ((double)sumv / ((double)sumv + 20.0));\n            beta = min(beta, 0.40);\n\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                prior[e] = clampd((1.0 - beta) * prior[e] + beta * fr.out[i], MIN_COST, MAX_COST);\n            }\n        }\n    }\n\n    Path random_monotone_path(int si, int sj, int ti, int tj) {\n        Path p;\n        int i = si, j = sj;\n        int rv = abs(ti - si);\n        int rh = abs(tj - sj);\n        char mv_v = (ti > si ? 'D' : 'U');\n        char mv_h = (tj > sj ? 'R' : 'L');\n\n        p.s.reserve(rv + rh);\n        p.edges.reserve(rv + rh);\n\n        while (rv > 0 || rh > 0) {\n            bool take_v;\n            if (rv == 0) take_v = false;\n            else if (rh == 0) take_v = true;\n            else take_v = (randint(1, rv + rh) <= rv);\n\n            if (take_v) {\n                int e;\n                if (mv_v == 'D') {\n                    e = vid(i, j);\n                    ++i;\n                } else {\n                    e = vid(i - 1, j);\n                    --i;\n                }\n                p.s.push_back(mv_v);\n                p.edges.push_back(e);\n                --rv;\n            } else {\n                int e;\n                if (mv_h == 'R') {\n                    e = hid(i, j);\n                    ++j;\n                } else {\n                    e = hid(i, j - 1);\n                    --j;\n                }\n                p.s.push_back(mv_h);\n                p.edges.push_back(e);\n                --rh;\n            }\n        }\n        finalize_path(p);\n        return p;\n    }\n\n    Path ordered_monotone_path(int si, int sj, int ti, int tj, bool horiz_first) {\n        Path p;\n        int i = si, j = sj;\n        int rh = abs(tj - sj);\n        int rv = abs(ti - si);\n        char ch = (tj > sj ? 'R' : 'L');\n        char cv = (ti > si ? 'D' : 'U');\n\n        p.s.reserve(rh + rv);\n        p.edges.reserve(rh + rv);\n\n        auto step_h = [&](char c) {\n            int e;\n            if (c == 'R') {\n                e = hid(i, j);\n                ++j;\n            } else {\n                e = hid(i, j - 1);\n                --j;\n            }\n            p.s.push_back(c);\n            p.edges.push_back(e);\n        };\n\n        auto step_v = [&](char c) {\n            int e;\n            if (c == 'D') {\n                e = vid(i, j);\n                ++i;\n            } else {\n                e = vid(i - 1, j);\n                --i;\n            }\n            p.s.push_back(c);\n            p.edges.push_back(e);\n        };\n\n        if (horiz_first) {\n            while (rh--) step_h(ch);\n            while (rv--) step_v(cv);\n        } else {\n            while (rv--) step_v(cv);\n            while (rh--) step_h(ch);\n        }\n\n        finalize_path(p);\n        return p;\n    }\n\n    double search_cost_adaptive(int e, double ucoef) const {\n        return plan_edge(e) + ucoef * unc_edge(e);\n    }\n\n    double search_cost_fixedmix(int e, double lambda_x, double ucoef) const {\n        double c = lambda_x * est_edge(e) + (1.0 - lambda_x) * prior[e];\n        c = clampd(c, MIN_COST, MAX_COST);\n        return c + ucoef * unc_edge(e);\n    }\n\n    Path dijkstra_adaptive(int si, int sj, int ti, int tj, double step_penalty, double ucoef) const {\n        const int V = N * N;\n        const double INF = 1e100;\n\n        vector<double> dist(V, INF);\n        vector<int> parent(V, -1), parent_edge(V, -1);\n        vector<char> parent_char(V, '?');\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        int s = node_id(si, sj), t = node_id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        auto relax = [&](int v, int ni, int nj, int e, char c) {\n            int nv = node_id(ni, nj);\n            double nd = dist[v] + search_cost_adaptive(e, ucoef) + step_penalty;\n            if (nd + 1e-12 < dist[nv]) {\n                dist[nv] = nd;\n                parent[nv] = v;\n                parent_edge[nv] = e;\n                parent_char[nv] = c;\n                pq.push({nd, nv});\n            }\n        };\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d > dist[v] + 1e-12) continue;\n            if (v == t) break;\n\n            int i = v / N;\n            int j = v % N;\n\n            if (i > 0) relax(v, i - 1, j, vid(i - 1, j), 'U');\n            if (i + 1 < N) relax(v, i + 1, j, vid(i, j), 'D');\n            if (j > 0) relax(v, i, j - 1, hid(i, j - 1), 'L');\n            if (j + 1 < N) relax(v, i, j + 1, hid(i, j), 'R');\n        }\n\n        Path res;\n        vector<char> rs;\n        vector<int> re;\n\n        for (int cur = t; cur != s; cur = parent[cur]) {\n            rs.push_back(parent_char[cur]);\n            re.push_back(parent_edge[cur]);\n        }\n        reverse(rs.begin(), rs.end());\n        reverse(re.begin(), re.end());\n\n        res.s.assign(rs.begin(), rs.end());\n        res.edges = move(re);\n        finalize_path(res);\n        return res;\n    }\n\n    Path dijkstra_fixedmix(int si, int sj, int ti, int tj, double step_penalty, double lambda_x, double ucoef) const {\n        const int V = N * N;\n        const double INF = 1e100;\n\n        vector<double> dist(V, INF);\n        vector<int> parent(V, -1), parent_edge(V, -1);\n        vector<char> parent_char(V, '?');\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        int s = node_id(si, sj), t = node_id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        auto relax = [&](int v, int ni, int nj, int e, char c) {\n            int nv = node_id(ni, nj);\n            double nd = dist[v] + search_cost_fixedmix(e, lambda_x, ucoef) + step_penalty;\n            if (nd + 1e-12 < dist[nv]) {\n                dist[nv] = nd;\n                parent[nv] = v;\n                parent_edge[nv] = e;\n                parent_char[nv] = c;\n                pq.push({nd, nv});\n            }\n        };\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d > dist[v] + 1e-12) continue;\n            if (v == t) break;\n\n            int i = v / N;\n            int j = v % N;\n\n            if (i > 0) relax(v, i - 1, j, vid(i - 1, j), 'U');\n            if (i + 1 < N) relax(v, i + 1, j, vid(i, j), 'D');\n            if (j > 0) relax(v, i, j - 1, hid(i, j - 1), 'L');\n            if (j + 1 < N) relax(v, i, j + 1, hid(i, j), 'R');\n        }\n\n        Path res;\n        vector<char> rs;\n        vector<int> re;\n\n        for (int cur = t; cur != s; cur = parent[cur]) {\n            rs.push_back(parent_char[cur]);\n            re.push_back(parent_edge[cur]);\n        }\n        reverse(rs.begin(), rs.end());\n        reverse(re.begin(), re.end());\n\n        res.s.assign(rs.begin(), rs.end());\n        res.edges = move(re);\n        finalize_path(res);\n        return res;\n    }\n\n    double robust_score(const Path& p, int qidx, double explore_bonus) const {\n        double wx;\n        if (qidx < 100) wx = 0.40;\n        else if (qidx < 250) wx = 0.50;\n        else if (qidx < 600) wx = 0.62;\n        else wx = 0.74;\n        double wp = 1.0 - wx;\n\n        double ucoef;\n        if (qidx < 120) ucoef = 110.0;\n        else if (qidx < 350) ucoef = 70.0;\n        else ucoef = 35.0;\n\n        double sc = wx * p.sumX + wp * p.sumPrior + ucoef * p.sumUnc;\n        sc -= explore_bonus * p.sumUnc;\n        return sc;\n    }\n\n    Path choose_path(int si, int sj, int ti, int tj, int qidx) {\n        bool explore = false;\n        int samples = 0;\n        double bonus = 0.0;\n\n        if (qidx < 90) {\n            explore = true;\n            samples = 18;\n            bonus = 230.0;\n        } else if (qidx < 150) {\n            explore = true;\n            samples = 8;\n            bonus = 160.0;\n        } else if (qidx < 320 && rand01() < 0.04) {\n            explore = true;\n            samples = 4;\n            bonus = 90.0;\n        }\n\n        double base_step = 35.0;\n        if (qidx < 220) {\n            base_step += 250.0 * (220 - qidx) / 220.0;\n        }\n\n        double u_adapt = (qidx < 160 ? 70.0 : qidx < 450 ? 40.0 : 20.0);\n        double u_x     = (qidx < 160 ? 100.0 : qidx < 450 ? 50.0 : 20.0);\n        double u_prior = (qidx < 160 ? 35.0 : qidx < 450 ? 20.0 : 10.0);\n\n        vector<Path> cands;\n        cands.reserve(32);\n\n        cands.push_back(dijkstra_adaptive(si, sj, ti, tj, base_step, u_adapt));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 1.0, u_x));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 0.0, u_prior));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 0.5, u_adapt));\n        cands.push_back(ordered_monotone_path(si, sj, ti, tj, true));\n        cands.push_back(ordered_monotone_path(si, sj, ti, tj, false));\n\n        if (qidx < 220) {\n            cands.push_back(dijkstra_adaptive(si, sj, ti, tj, 0.0, u_adapt * 0.7));\n        }\n\n        if (explore) {\n            for (int t = 0; t < samples; ++t) {\n                cands.push_back(random_monotone_path(si, sj, ti, tj));\n            }\n        }\n\n        int best_id = 0;\n        double best_sc = robust_score(cands[0], qidx, explore ? bonus : 0.0);\n\n        for (int i = 1; i < (int)cands.size(); ++i) {\n            double sc = robust_score(cands[i], qidx, explore ? bonus : 0.0);\n            if (sc + 1e-12 < best_sc) {\n                best_sc = sc;\n                best_id = i;\n            } else if (fabs(sc - best_sc) < 1e-12) {\n                if (cands[i].edges.size() < cands[best_id].edges.size()) best_id = i;\n            }\n        }\n        return cands[best_id];\n    }\n\n    void online_update(const Path& path, double y, int qidx) {\n        int m = (int)path.edges.size();\n        if (m == 0) return;\n\n        double pred = path.sumX;\n        double residual = y - pred;\n\n        double eta;\n        if (qidx < 120) eta = 0.30;\n        else if (qidx < 350) eta = 0.22;\n        else eta = 0.16;\n\n        vector<double> u(m);\n        double su = 0.0;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            u[k] = 1.0 / sqrt((double)vis[e] + 1.0);\n            su += u[k];\n        }\n        if (su < 1e-12) su = 1.0;\n\n        double scale = eta * residual / su;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            double delta = scale * u[k];\n            delta = clampd(delta, -900.0, 900.0);\n            x[e] = clampd(x[e] + delta, MIN_COST, MAX_COST);\n        }\n\n        for (int e : path.edges) vis[e]++;\n        hist.push_back(make_observation(path, y));\n    }\n\n    void global_refine() {\n        int nobs = (int)hist.size();\n        if (nobs == 0) return;\n\n        build_prior();\n\n        double lambda0 = 0.10 / sqrt((double)nobs + 1.0) + 0.020;\n        double lambda1 = 0.32 / sqrt((double)nobs + 1.0) + 0.035;\n\n        vector<double> alpha(E), rhs(E, 0.0);\n        for (int e = 0; e < E; ++e) {\n            alpha[e] = 1.0 / sqrt((double)vis[e] + 1.0);\n            rhs[e] = lambda0 * alpha[e] * prior[e];\n        }\n\n        for (const auto& ob : hist) {\n            double c = ob.w * ob.y;\n            for (int e : ob.edges) rhs[e] += c;\n        }\n\n        auto apply = [&](const vector<double>& p, vector<double>& out) {\n            out.assign(E, 0.0);\n\n            for (int e = 0; e < E; ++e) {\n                out[e] = lambda0 * alpha[e] * p[e];\n            }\n\n            for (const auto& ob : hist) {\n                double s = 0.0;\n                for (int e : ob.edges) s += p[e];\n                s *= ob.w;\n                for (int e : ob.edges) out[e] += s;\n            }\n\n            for (int i = 0; i < 30; ++i) {\n                for (int j = 0; j < 28; ++j) {\n                    int e1 = hid(i, j);\n                    int e2 = hid(i, j + 1);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n\n            for (int j = 0; j < 30; ++j) {\n                for (int i = 0; i < 28; ++i) {\n                    int e1 = vid(i, j);\n                    int e2 = vid(i + 1, j);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n        };\n\n        vector<double> sol = x, r(E), p(E), Ap(E);\n        apply(sol, Ap);\n        for (int e = 0; e < E; ++e) r[e] = rhs[e] - Ap[e];\n        p = r;\n\n        double rs0 = dot_vec(r, r);\n        double rs = rs0;\n        if (rs < 1e-12) return;\n\n        const int ITERS = 28;\n        for (int it = 0; it < ITERS; ++it) {\n            apply(p, Ap);\n            double pAp = dot_vec(p, Ap);\n            if (pAp <= 1e-18) break;\n\n            double a = rs / pAp;\n            for (int e = 0; e < E; ++e) sol[e] += a * p[e];\n            for (int e = 0; e < E; ++e) r[e] -= a * Ap[e];\n\n            double rs_new = dot_vec(r, r);\n            if (rs_new < rs0 * 1e-10) break;\n\n            double b = rs_new / rs;\n            for (int e = 0; e < E; ++e) p[e] = r[e] + b * p[e];\n            rs = rs_new;\n        }\n\n        for (int e = 0; e < E; ++e) {\n            x[e] = clampd(sol[e], MIN_COST, MAX_COST);\n        }\n\n        for (int e = 0; e < E; ++e) {\n            double g = 0.10 / sqrt((double)vis[e] + 1.0);\n            x[e] = clampd((1.0 - g) * x[e] + g * prior[e], MIN_COST, MAX_COST);\n        }\n\n        build_prior();\n    }\n\n    bool should_refine(int qq) const {\n        if (qq <= 160) return qq % 20 == 0;\n        if (qq <= 400) return qq % 40 == 0;\n        return qq % 50 == 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        Path path = solver.choose_path(si, sj, ti, tj, q);\n\n        cout << path.s << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.online_update(path, (double)result, q);\n\n        int qq = q + 1;\n        if (solver.should_refine(qq)) {\n            solver.global_refine();\n        }\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nusing Matrix = array<unsigned char, N * N>;\n\nstruct Candidate {\n    string row;\n    vector<int> cover;\n    int totalWeight = 0;\n};\n\nstruct Move {\n    long long val;\n    string s;\n};\n\nstruct Edge {\n    int pid;\n    unsigned char req;\n};\n\nstruct StartResult {\n    long long score;\n    Matrix mat;\n};\n\nstruct RowState {\n    array<int, N> ord{};\n    array<int, N> sh{};\n    long long sc = LLONG_MIN;\n};\n\nstruct CellChange {\n    int cell;\n    unsigned char oldc;\n    unsigned char newc;\n};\n\nstatic chrono::steady_clock::time_point gStart;\nstatic inline long long elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - gStart\n    ).count();\n}\n\nmt19937 rng((unsigned)chrono::steady_clock::now().time_since_epoch().count());\n\n// compressed input\nvector<string> pats;\nvector<vector<unsigned char>> pch;\nvector<int> wt;\nvector<int> impOrder;\n\n// exact local search graph (all placements)\nvector<vector<Edge>> cellEdges; // 400 cells\nvector<int> plSid;\nvector<unsigned char> plLen;\nvector<unsigned char> plMatch;\n\n// vertical-only graph for zero-cost row operations\nvector<vector<Edge>> vCellEdges; // 400 cells\nvector<int> vPlSid;\nvector<unsigned char> vPlLen;\nvector<unsigned char> vPlMatch;\n\n// n-gram weights\nlong long pairW[8][8];\nlong long triW[8][8][8];\n\n// ---------------- row candidate generation utilities ----------------\n\ninline bool contains_in_doubled(const char* dd, const string& p) {\n    const int k = (int)p.size();\n    const char* ps = p.data();\n    for (int st = 0; st < N; ++st) {\n        int j = 0;\n        while (j < k && dd[st + j] == ps[j]) ++j;\n        if (j == k) return true;\n    }\n    return false;\n}\n\nint overlap_suffix_prefix(const string& a, const string& b) {\n    int lim = min((int)a.size(), (int)b.size());\n    for (int o = lim; o >= 1; --o) {\n        bool ok = true;\n        int sa = (int)a.size() - o;\n        for (int i = 0; i < o; ++i) {\n            if (a[sa + i] != b[i]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) return o;\n    }\n    return 0;\n}\n\nstring repeat_to_20(const string& s) {\n    if ((int)s.size() == N) return s;\n    string r(N, 'A');\n    for (int i = 0; i < N; ++i) r[i] = s[i % (int)s.size()];\n    return r;\n}\n\nstring min_rotation(const string& s) {\n    string best = s;\n    for (int sh = 1; sh < N; ++sh) {\n        string t = s.substr(sh) + s.substr(0, sh);\n        if (t < best) best = t;\n    }\n    return best;\n}\n\nvoid push_top(vector<Move>& top, long long val, const string& s, int cap = 4) {\n    if (val <= 0) return;\n    top.push_back({val, s});\n    int pos = (int)top.size() - 1;\n    while (pos > 0 && top[pos].val > top[pos - 1].val) {\n        swap(top[pos], top[pos - 1]);\n        --pos;\n    }\n    if ((int)top.size() > cap) top.pop_back();\n}\n\nstring choose_move(const vector<Move>& top, bool randomized) {\n    if (top.empty()) return \"\";\n    if (!randomized || top.size() == 1) return top[0].s;\n    int k = min<int>(3, top.size());\n    int r = (int)(rng() % 10);\n    int idx = 0;\n    if (k >= 3) {\n        if (r < 6) idx = 0;\n        else if (r < 9) idx = 1;\n        else idx = 2;\n    } else if (k == 2) {\n        idx = (r < 7 ? 0 : 1);\n    }\n    return top[idx].s;\n}\n\nstring build_candidate_row(int seedId, bool randomized) {\n    string cur = pats[seedId];\n    int scanLim = min<int>((int)impOrder.size(), 240);\n\n    // phase 0: strong overlap / containment\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            if ((int)x.size() > (int)cur.size()) {\n                if (x.find(cur) != string::npos && (int)x.size() <= N) {\n                    long long val = 1LL * wt[id] * 3000 + 1LL * ((int)x.size() - (int)cur.size()) * 200;\n                    push_top(top, val, x);\n                }\n            }\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty()) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    // phase 1: pack more strings\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty() || top[0].val <= 0) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    return repeat_to_20(cur);\n}\n\nvector<string> build_initial_rows(const vector<int>& charFreq) {\n    int U = (int)pats.size();\n    vector<Candidate> cands;\n    cands.reserve(400);\n\n    unordered_set<string> seen;\n    seen.reserve(2048);\n\n    auto add_candidate = [&](string row) {\n        if ((int)row.size() != N) row = repeat_to_20(row);\n        row = min_rotation(row);\n        if (!seen.insert(row).second) return;\n\n        char dd[40];\n        for (int i = 0; i < N; ++i) dd[i] = dd[i + N] = row[i];\n\n        Candidate cand;\n        cand.row = row;\n        cand.totalWeight = 0;\n        for (int id = 0; id < U; ++id) {\n            if (contains_in_doubled(dd, pats[id])) {\n                cand.cover.push_back(id);\n                cand.totalWeight += wt[id];\n            }\n        }\n        if (!cand.cover.empty()) cands.push_back(std::move(cand));\n    };\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n\n    for (int c = 0; c < 8; ++c) add_candidate(string(N, char('A' + c)));\n\n    for (int t = 0; t < min(U, 70); ++t) {\n        add_candidate(repeat_to_20(pats[impOrder[t]]));\n    }\n\n    for (int t = 0; t < min(U, 90); ++t) {\n        add_candidate(build_candidate_row(impOrder[t], false));\n        if (elapsed_ms() > 500) break;\n    }\n\n    for (int t = 0; t < 50; ++t) {\n        int lim = min(U, max(1, 40 + t * 2));\n        int seedId = impOrder[(int)(rng() % lim)];\n        add_candidate(build_candidate_row(seedId, true));\n        if (elapsed_ms() > 700) break;\n    }\n\n    if ((int)cands.size() < 20) {\n        for (int a = 0; a < 8; ++a) {\n            for (int b = 0; b < 8; ++b) {\n                string s(N, 'A');\n                for (int i = 0; i < N; ++i) s[i] = char('A' + ((i & 1) ? b : a));\n                add_candidate(s);\n                if ((int)cands.size() >= 20) break;\n            }\n            if ((int)cands.size() >= 20) break;\n        }\n    }\n\n    if (cands.empty()) {\n        vector<string> rows(20, string(N, char('A' + bestChar)));\n        return rows;\n    }\n\n    int C = (int)cands.size();\n\n    vector<int> selected;\n    selected.reserve(20);\n    vector<char> usedCand(C, 0);\n    vector<char> covered(U, 0);\n\n    for (int step = 0; step < 20 && step < C; ++step) {\n        int best = -1;\n        long long bestGain = -1;\n        int bestTotal = -1;\n        for (int ci = 0; ci < C; ++ci) if (!usedCand[ci]) {\n            long long gain = 0;\n            for (int id : cands[ci].cover) if (!covered[id]) gain += wt[id];\n            if (gain > bestGain || (gain == bestGain && cands[ci].totalWeight > bestTotal)) {\n                bestGain = gain;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n        if (best == -1) break;\n        usedCand[best] = 1;\n        selected.push_back(best);\n        for (int id : cands[best].cover) covered[id] = 1;\n    }\n\n    if ((int)selected.size() < 20) {\n        vector<int> ord(C);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return cands[a].totalWeight > cands[b].totalWeight;\n        });\n        for (int ci : ord) {\n            if ((int)selected.size() >= 20) break;\n            if (!usedCand[ci]) {\n                usedCand[ci] = 1;\n                selected.push_back(ci);\n            }\n        }\n    }\n    while ((int)selected.size() < 20) selected.push_back(selected[0]);\n\n    vector<int> coverCnt(U, 0);\n    long long rowWeight = 0;\n    fill(usedCand.begin(), usedCand.end(), 0);\n    for (int ci : selected) usedCand[ci] = 1;\n    for (int ci : selected) {\n        for (int id : cands[ci].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    for (int pos = 0; pos < 20; ++pos) {\n        int old = selected[pos];\n        usedCand[old] = 0;\n        for (int id : cands[old].cover) {\n            if (--coverCnt[id] == 0) rowWeight -= wt[id];\n        }\n\n        int best = old;\n        long long bestScore = rowWeight;\n        int bestTotal = cands[old].totalWeight;\n\n        for (int ci = 0; ci < C; ++ci) {\n            if (usedCand[ci]) continue;\n            long long sc = rowWeight;\n            for (int id : cands[ci].cover) {\n                if (coverCnt[id] == 0) sc += wt[id];\n            }\n            if (sc > bestScore || (sc == bestScore && cands[ci].totalWeight > bestTotal)) {\n                bestScore = sc;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n\n        selected[pos] = best;\n        usedCand[best] = 1;\n        for (int id : cands[best].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    vector<string> rows(20);\n    for (int i = 0; i < 20; ++i) rows[i] = cands[selected[i]].row;\n    return rows;\n}\n\n// ---------------- exact graph ----------------\n\nvoid build_exact_graph() {\n    int U = (int)pats.size();\n\n    cellEdges.assign(N * N, {});\n    vCellEdges.assign(N * N, {});\n\n    long long totalEdgesAll = 0;\n    long long totalEdgesV = 0;\n    for (int sid = 0; sid < U; ++sid) {\n        totalEdgesAll += 800LL * (int)pats[sid].size();\n        totalEdgesV += 400LL * (int)pats[sid].size();\n    }\n\n    int reserveAll = (int)(totalEdgesAll / (N * N)) + 64;\n    int reserveV = (int)(totalEdgesV / (N * N)) + 32;\n    for (int c = 0; c < N * N; ++c) {\n        cellEdges[c].reserve(reserveAll);\n        vCellEdges[c].reserve(reserveV);\n    }\n\n    plSid.clear();\n    plLen.clear();\n    plMatch.clear();\n    plSid.reserve(U * 800);\n    plLen.reserve(U * 800);\n    plMatch.reserve(U * 800);\n\n    vPlSid.clear();\n    vPlLen.clear();\n    vPlMatch.clear();\n    vPlSid.reserve(U * 400);\n    vPlLen.reserve(U * 400);\n    vPlMatch.reserve(U * 400);\n\n    for (int sid = 0; sid < U; ++sid) {\n        const auto& s = pch[sid];\n        int k = (int)s.size();\n\n        // horizontal placements\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n\n                int base = r * N;\n                for (int t = 0; t < k; ++t) {\n                    int cell = base + ((c + t) % N);\n                    cellEdges[cell].push_back({pid, s[t]});\n                }\n            }\n        }\n\n        // vertical placements\n        for (int c = 0; c < N; ++c) {\n            for (int r = 0; r < N; ++r) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n\n                int vpid = (int)vPlSid.size();\n                vPlSid.push_back(sid);\n                vPlLen.push_back((unsigned char)k);\n                vPlMatch.push_back(0);\n\n                for (int t = 0; t < k; ++t) {\n                    int cell = ((r + t) % N) * N + c;\n                    cellEdges[cell].push_back({pid, s[t]});\n                    vCellEdges[cell].push_back({vpid, s[t]});\n                }\n            }\n        }\n    }\n}\n\nlong long init_state(const Matrix& mat, vector<int>& fullCnt) {\n    fill(plMatch.begin(), plMatch.end(), 0);\n    for (int cell = 0; cell < N * N; ++cell) {\n        unsigned char ch = mat[cell];\n        for (const auto& e : cellEdges[cell]) {\n            if (e.req == ch) ++plMatch[e.pid];\n        }\n    }\n\n    fullCnt.assign(pats.size(), 0);\n    for (int pid = 0, P = (int)plSid.size(); pid < P; ++pid) {\n        if (plMatch[pid] == plLen[pid]) ++fullCnt[plSid[pid]];\n    }\n\n    long long score = 0;\n    for (int sid = 0; sid < (int)pats.size(); ++sid) {\n        if (fullCnt[sid] > 0) score += wt[sid];\n    }\n    return score;\n}\n\nvoid init_vertical_state(const Matrix& mat) {\n    fill(vPlMatch.begin(), vPlMatch.end(), 0);\n    for (int cell = 0; cell < N * N; ++cell) {\n        unsigned char ch = mat[cell];\n        for (const auto& e : vCellEdges[cell]) {\n            if (e.req == ch) ++vPlMatch[e.pid];\n        }\n    }\n}\n\n// ---------------- matrix utilities ----------------\n\nMatrix transpose_matrix(const Matrix& a) {\n    Matrix b{};\n    for (int r = 0; r < N; ++r)\n        for (int c = 0; c < N; ++c)\n            b[c * N + r] = a[r * N + c];\n    return b;\n}\n\nMatrix make_matrix_from_rows(const vector<string>& rows, bool randomizeOrderShift, bool doTranspose) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    if (randomizeOrderShift) shuffle(ord.begin(), ord.end(), rng);\n\n    Matrix mat{};\n    for (int r = 0; r < N; ++r) {\n        const string& s = rows[ord[r]];\n        int sh = randomizeOrderShift ? (int)(rng() % N) : 0;\n        for (int c = 0; c < N; ++c) mat[r * N + c] = (unsigned char)(s[(c + sh) % N] - 'A');\n    }\n    if (doTranspose) mat = transpose_matrix(mat);\n    return mat;\n}\n\nMatrix make_constant_matrix(int ch) {\n    Matrix mat{};\n    for (int i = 0; i < N * N; ++i) mat[i] = (unsigned char)ch;\n    return mat;\n}\n\nMatrix make_random_freq_matrix(const vector<int>& charFreq) {\n    array<int, 8> pref{};\n    pref[0] = charFreq[0];\n    for (int i = 1; i < 8; ++i) pref[i] = pref[i - 1] + charFreq[i];\n    int total = pref[7];\n    Matrix mat{};\n    for (int i = 0; i < N * N; ++i) {\n        int x = (int)(rng() % total);\n        int ch = 0;\n        while (pref[ch] <= x) ++ch;\n        mat[i] = (unsigned char)ch;\n    }\n    return mat;\n}\n\n// ---------------- row order / shift optimization by n-grams ----------------\n\nvector<Matrix> build_ngram_starts(const vector<string>& rows) {\n    unsigned char rowChars[N][N][N];\n    for (int r = 0; r < N; ++r) {\n        for (int sh = 0; sh < N; ++sh) {\n            for (int c = 0; c < N; ++c) {\n                rowChars[r][sh][c] = (unsigned char)(rows[r][(c + sh) % N] - 'A');\n            }\n        }\n    }\n\n    auto totalScore = [&](const array<int, N>& ord, const array<int, N>& sh) -> long long {\n        long long sc = 0;\n        for (int p = 0; p < N; ++p) {\n            int a = ord[p];\n            int b = ord[(p + 1) % N];\n            int c = ord[(p + 2) % N];\n            int sa = sh[p];\n            int sb = sh[(p + 1) % N];\n            int scv = sh[(p + 2) % N];\n            for (int col = 0; col < N; ++col) {\n                unsigned char x = rowChars[a][sa][col];\n                unsigned char y = rowChars[b][sb][col];\n                unsigned char z = rowChars[c][scv][col];\n                sc += pairW[x][y];\n                sc += 2LL * triW[x][y][z];\n            }\n        }\n        return sc;\n    };\n\n    auto optimize_state = [&](RowState st) -> RowState {\n        st.sc = totalScore(st.ord, st.sh);\n\n        for (int it = 0; it < 8; ++it) {\n            bool improved = false;\n\n            for (int p = 0; p < N; ++p) {\n                int bestSh = st.sh[p];\n                long long bestSc = st.sc;\n                int old = st.sh[p];\n                for (int cand = 0; cand < N; ++cand) {\n                    st.sh[p] = cand;\n                    long long sc = totalScore(st.ord, st.sh);\n                    if (sc > bestSc) {\n                        bestSc = sc;\n                        bestSh = cand;\n                    }\n                }\n                st.sh[p] = bestSh;\n                if (bestSc > st.sc) {\n                    st.sc = bestSc;\n                    improved = true;\n                } else {\n                    st.sh[p] = old;\n                }\n            }\n\n            while (true) {\n                int bi = -1, bj = -1;\n                long long bestSc = st.sc;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = i + 1; j < N; ++j) {\n                        swap(st.ord[i], st.ord[j]);\n                        swap(st.sh[i], st.sh[j]);\n                        long long sc = totalScore(st.ord, st.sh);\n                        swap(st.ord[i], st.ord[j]);\n                        swap(st.sh[i], st.sh[j]);\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                swap(st.ord[bi], st.ord[bj]);\n                swap(st.sh[bi], st.sh[bj]);\n                st.sc = bestSc;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return st;\n    };\n\n    vector<RowState> states;\n    auto make_state = [&](bool randOrd, bool randSh) {\n        RowState st;\n        for (int i = 0; i < N; ++i) st.ord[i] = i;\n        if (randOrd) shuffle(st.ord.begin(), st.ord.end(), rng);\n        for (int i = 0; i < N; ++i) st.sh[i] = randSh ? (int)(rng() % N) : 0;\n        return optimize_state(st);\n    };\n\n    states.push_back(make_state(false, false));\n    states.push_back(make_state(false, true));\n    states.push_back(make_state(true, false));\n    for (int t = 0; t < 4; ++t) states.push_back(make_state(true, true));\n\n    sort(states.begin(), states.end(), [&](const RowState& a, const RowState& b) {\n        return a.sc > b.sc;\n    });\n\n    auto state_to_matrix = [&](const RowState& st, bool transposed) {\n        Matrix mat{};\n        for (int r = 0; r < N; ++r) {\n            int rowId = st.ord[r];\n            int sh = st.sh[r];\n            for (int c = 0; c < N; ++c) {\n                mat[r * N + c] = rowChars[rowId][sh][c];\n            }\n        }\n        if (transposed) mat = transpose_matrix(mat);\n        return mat;\n    };\n\n    vector<Matrix> starts;\n    int lim = min<int>(4, states.size());\n    for (int i = 0; i < lim; ++i) {\n        starts.push_back(state_to_matrix(states[i], false));\n        starts.push_back(state_to_matrix(states[i], true));\n    }\n    return starts;\n}\n\n// ---------------- soft refinement ----------------\n\nStartResult soft_refine(Matrix mat, const vector<int>& kinds, const vector<int>& inertias, long long deadlineMs) {\n    vector<int> tmpFull;\n    StartResult best{init_state(mat, tmpFull), mat};\n\n    for (int pi = 0; pi < (int)kinds.size(); ++pi) {\n        if (elapsed_ms() > deadlineMs) break;\n\n        int kind = kinds[pi];\n        int inertia = inertias[pi];\n\n        long long votes[N * N][8];\n        memset(votes, 0, sizeof(votes));\n\n        for (int cell = 0; cell < N * N; ++cell) votes[cell][mat[cell]] += inertia;\n\n        unsigned char row2[N][2 * N];\n        unsigned char col2[N][2 * N];\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < 2 * N; ++c)\n                row2[r][c] = mat[r * N + (c % N)];\n        for (int c = 0; c < N; ++c)\n            for (int r = 0; r < 2 * N; ++r)\n                col2[c][r] = mat[(r % N) * N + c];\n\n        for (int sid = 0; sid < (int)pats.size(); ++sid) {\n            const auto& s = pch[sid];\n            int k = (int)s.size();\n\n            unsigned char scs[800];\n            int idx = 0;\n            int bestSc = -1;\n\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (row2[r][c + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n            for (int c = 0; c < N; ++c) {\n                for (int r = 0; r < N; ++r) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (col2[c][r + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n\n            int req, band;\n            long long base0, base1, base2;\n\n            if (kind == 0) {\n                req = max(3, (k + 1) / 2);\n                band = 0;\n                base0 = 64; base1 = 0; base2 = 0;\n            } else if (kind == 1) {\n                req = max(3, k / 2);\n                band = 1;\n                base0 = 48; base1 = 10; base2 = 0;\n            } else if (kind == 2) {\n                req = max(2, (k - 1) / 2);\n                band = 1;\n                base0 = 40; base1 = 14; base2 = 0;\n            } else if (kind == 3) {\n                req = 2;\n                band = 2;\n                base0 = 32; base1 = 12; base2 = 4;\n            } else if (kind == 4) {\n                req = max(2, k / 3);\n                band = 2;\n                base0 = 28; base1 = 12; base2 = 4;\n            } else {\n                req = 2;\n                band = 2;\n                base0 = 20; base1 = 10; base2 = 5;\n            }\n\n            if (bestSc < req) continue;\n\n            const int cap0 = 6, cap1 = 4, cap2 = 2;\n            int sel0[cap0], sel1[cap1], sel2[cap2];\n            int n0 = 0, n1 = 0, n2 = 0;\n            int seen0 = 0, seen1 = 0, seen2 = 0;\n\n            auto reservoir_add = [&](int* arr, int& n, int cap, int& seen, int code) {\n                ++seen;\n                if (n < cap) {\n                    arr[n++] = code;\n                } else {\n                    int r = (int)(rng() % seen);\n                    if (r < cap) arr[r] = code;\n                }\n            };\n\n            for (int code = 0; code < 800; ++code) {\n                int d = bestSc - (int)scs[code];\n                if (d == 0) reservoir_add(sel0, n0, cap0, seen0, code);\n                else if (d == 1 && band >= 1) reservoir_add(sel1, n1, cap1, seen1, code);\n                else if (d == 2 && band >= 2) reservoir_add(sel2, n2, cap2, seen2, code);\n            }\n\n            long long total0 = 1LL * wt[sid] * k * base0;\n            long long total1 = 1LL * wt[sid] * k * base1;\n            long long total2 = 1LL * wt[sid] * k * base2;\n\n            auto add_code = [&](int code, long long w) {\n                if (w <= 0) return;\n                if (code < 400) {\n                    int r = code / N;\n                    int c = code % N;\n                    int base = r * N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = base + ((c + t) % N);\n                        votes[cell][s[t]] += w;\n                    }\n                } else {\n                    int x = code - 400;\n                    int c = x / N;\n                    int r = x % N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = ((r + t) % N) * N + c;\n                        votes[cell][s[t]] += w;\n                    }\n                }\n            };\n\n            if (n0 > 0) {\n                long long w = total0 / n0;\n                for (int i = 0; i < n0; ++i) add_code(sel0[i], w);\n            }\n            if (n1 > 0) {\n                long long w = total1 / n1;\n                for (int i = 0; i < n1; ++i) add_code(sel1[i], w);\n            }\n            if (n2 > 0) {\n                long long w = total2 / n2;\n                for (int i = 0; i < n2; ++i) add_code(sel2[i], w);\n            }\n        }\n\n        int changes = 0;\n        for (int cell = 0; cell < N * N; ++cell) {\n            unsigned char old = mat[cell];\n            unsigned char bestCh = old;\n            long long bestV = votes[cell][old];\n            for (unsigned char ch = 0; ch < 8; ++ch) {\n                if (votes[cell][ch] > bestV) {\n                    bestV = votes[cell][ch];\n                    bestCh = ch;\n                }\n            }\n            if (bestCh != old) {\n                mat[cell] = bestCh;\n                ++changes;\n            }\n        }\n\n        long long sc = init_state(mat, tmpFull);\n        if (sc > best.score) best = {sc, mat};\n        if (changes == 0) break;\n    }\n\n    return best;\n}\n\n// ---------------- exact hill-climb ----------------\n\nStartResult exact_hillclimb(Matrix mat, int maxPass, long long endMs) {\n    vector<int> fullCnt;\n    long long curScore = init_state(mat, fullCnt);\n    StartResult best{curScore, mat};\n\n    vector<int> order(N * N);\n    iota(order.begin(), order.end(), 0);\n\n    int U = (int)pats.size();\n    vector<int> seen(U, 0), inc(U, 0), dec(U, 0), touched;\n    touched.reserve(U);\n    int stamp = 1;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        if (elapsed_ms() > endMs) break;\n        shuffle(order.begin(), order.end(), rng);\n        bool improved = false;\n\n        for (int cell : order) {\n            if (elapsed_ms() > endMs) break;\n\n            unsigned char old = mat[cell];\n            long long bestDelta = 0;\n            unsigned char bestCh = old;\n\n            for (unsigned char nw = 0; nw < 8; ++nw) {\n                if (nw == old) continue;\n                ++stamp;\n                touched.clear();\n\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == nw);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n\n                    if (seen[sid] != stamp) {\n                        seen[sid] = stamp;\n                        inc[sid] = 0;\n                        dec[sid] = 0;\n                        touched.push_back(sid);\n                    }\n\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) ++dec[sid];\n                    } else {\n                        if ((int)plMatch[pid] + 1 == (int)plLen[pid]) ++inc[sid];\n                    }\n                }\n\n                long long delta = 0;\n                for (int sid : touched) {\n                    int oldCnt = fullCnt[sid];\n                    int newCnt = oldCnt - dec[sid] + inc[sid];\n                    if (oldCnt == 0 && newCnt > 0) delta += wt[sid];\n                    else if (oldCnt > 0 && newCnt == 0) delta -= wt[sid];\n                }\n\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestCh = nw;\n                }\n            }\n\n            if (bestCh != old) {\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == bestCh);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) --fullCnt[sid];\n                        --plMatch[pid];\n                    } else {\n                        ++plMatch[pid];\n                        if (plMatch[pid] == plLen[pid]) ++fullCnt[sid];\n                    }\n                }\n                mat[cell] = bestCh;\n                curScore += bestDelta;\n                improved = true;\n                if (curScore > best.score) best = {curScore, mat};\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return best;\n}\n\n// ---------------- exact zero-cost row optimizer ----------------\n\nlong long compute_vertical_delta(\n    const CellChange* chgs, int m,\n    const vector<int>& totalFullCnt,\n    vector<int>& pidSeen, vector<int>& pidDelta, int& pidStamp, vector<int>& touchedPid,\n    vector<int>& sidSeen, vector<int>& sidInc, vector<int>& sidDec, int& sidStamp, vector<int>& touchedSid\n) {\n    ++pidStamp;\n    if (pidStamp == INT_MAX) {\n        fill(pidSeen.begin(), pidSeen.end(), 0);\n        pidStamp = 1;\n    }\n    touchedPid.clear();\n\n    for (int i = 0; i < m; ++i) {\n        int cell = chgs[i].cell;\n        unsigned char oldc = chgs[i].oldc;\n        unsigned char newc = chgs[i].newc;\n        if (oldc == newc) continue;\n\n        for (const auto& e : vCellEdges[cell]) {\n            int vpid = e.pid;\n            if (pidSeen[vpid] != pidStamp) {\n                pidSeen[vpid] = pidStamp;\n                pidDelta[vpid] = 0;\n                touchedPid.push_back(vpid);\n            }\n            if (e.req == oldc) --pidDelta[vpid];\n            if (e.req == newc) ++pidDelta[vpid];\n        }\n    }\n\n    ++sidStamp;\n    if (sidStamp == INT_MAX) {\n        fill(sidSeen.begin(), sidSeen.end(), 0);\n        sidStamp = 1;\n    }\n    touchedSid.clear();\n\n    for (int vpid : touchedPid) {\n        int d = pidDelta[vpid];\n        if (d == 0) continue;\n        int sid = vPlSid[vpid];\n        if (sidSeen[sid] != sidStamp) {\n            sidSeen[sid] = sidStamp;\n            sidInc[sid] = 0;\n            sidDec[sid] = 0;\n            touchedSid.push_back(sid);\n        }\n\n        int oldm = vPlMatch[vpid];\n        int newm = oldm + d;\n        int len = vPlLen[vpid];\n\n        if (oldm == len && newm < len) ++sidDec[sid];\n        else if (oldm < len && newm == len) ++sidInc[sid];\n    }\n\n    long long delta = 0;\n    for (int sid : touchedSid) {\n        int oldCnt = totalFullCnt[sid];\n        int newCnt = oldCnt - sidDec[sid] + sidInc[sid];\n        if (oldCnt == 0 && newCnt > 0) delta += wt[sid];\n        else if (oldCnt > 0 && newCnt == 0) delta -= wt[sid];\n    }\n    return delta;\n}\n\nvoid apply_vertical_changes(\n    Matrix& mat,\n    const CellChange* chgs, int m,\n    vector<int>& totalFullCnt, long long& curScore,\n    vector<int>& pidSeen, vector<int>& pidDelta, int& pidStamp, vector<int>& touchedPid,\n    vector<int>& sidSeen, vector<int>& sidInc, vector<int>& sidDec, int& sidStamp, vector<int>& touchedSid\n) {\n    long long delta = compute_vertical_delta(\n        chgs, m, totalFullCnt,\n        pidSeen, pidDelta, pidStamp, touchedPid,\n        sidSeen, sidInc, sidDec, sidStamp, touchedSid\n    );\n\n    for (int vpid : touchedPid) {\n        int d = pidDelta[vpid];\n        if (d == 0) continue;\n        int oldm = vPlMatch[vpid];\n        int newm = oldm + d;\n        int sid = vPlSid[vpid];\n        int len = vPlLen[vpid];\n\n        if (oldm == len && newm < len) --totalFullCnt[sid];\n        else if (oldm < len && newm == len) ++totalFullCnt[sid];\n\n        vPlMatch[vpid] = (unsigned char)newm;\n    }\n\n    for (int i = 0; i < m; ++i) {\n        mat[chgs[i].cell] = chgs[i].newc;\n    }\n\n    curScore += delta;\n}\n\nStartResult exact_row_optimize(Matrix mat, long long endMs) {\n    vector<int> totalFullCnt;\n    long long curScore = init_state(mat, totalFullCnt);\n    init_vertical_state(mat);\n\n    const int U = (int)pats.size();\n    const int V = (int)vPlSid.size();\n\n    vector<int> pidSeen(V, 0), pidDelta(V, 0), touchedPid;\n    vector<int> sidSeen(U, 0), sidInc(U, 0), sidDec(U, 0), touchedSid;\n    touchedPid.reserve(160000);\n    touchedSid.reserve(U);\n\n    int pidStamp = 1, sidStamp = 1;\n\n    array<int, N> rowOrder{};\n    iota(rowOrder.begin(), rowOrder.end(), 0);\n\n    array<CellChange, N> shiftChg{};\n    array<CellChange, 2 * N> swapChg{};\n\n    for (int outer = 0; outer < 2; ++outer) {\n        if (elapsed_ms() > endMs) break;\n        bool improved = false;\n\n        shuffle(rowOrder.begin(), rowOrder.end(), rng);\n\n        // row cyclic shifts\n        for (int rr = 0; rr < N; ++rr) {\n            if (elapsed_ms() > endMs) break;\n            int r = rowOrder[rr];\n            int base = r * N;\n\n            unsigned char oldRow[N];\n            for (int c = 0; c < N; ++c) oldRow[c] = mat[base + c];\n\n            long long bestDelta = 0;\n            int bestSh = 0;\n\n            for (int sh = 1; sh < N; ++sh) {\n                for (int c = 0; c < N; ++c) {\n                    shiftChg[c] = {base + c, oldRow[c], oldRow[(c + sh) % N]};\n                }\n\n                long long delta = compute_vertical_delta(\n                    shiftChg.data(), N, totalFullCnt,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestSh = sh;\n                }\n            }\n\n            if (bestSh != 0) {\n                for (int c = 0; c < N; ++c) {\n                    shiftChg[c] = {base + c, oldRow[c], oldRow[(c + bestSh) % N]};\n                }\n                apply_vertical_changes(\n                    mat, shiftChg.data(), N, totalFullCnt, curScore,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                improved = true;\n            }\n        }\n\n        if (elapsed_ms() > endMs) break;\n\n        // row swaps (best-improvement, a few times)\n        for (int rep = 0; rep < 2; ++rep) {\n            if (elapsed_ms() > endMs) break;\n\n            long long bestDelta = 0;\n            int bi = -1, bj = -1;\n\n            for (int i = 0; i < N; ++i) {\n                if (elapsed_ms() > endMs) break;\n                int baseI = i * N;\n                for (int j = i + 1; j < N; ++j) {\n                    int baseJ = j * N;\n                    for (int c = 0; c < N; ++c) {\n                        swapChg[2 * c] = {baseI + c, mat[baseI + c], mat[baseJ + c]};\n                        swapChg[2 * c + 1] = {baseJ + c, mat[baseJ + c], mat[baseI + c]};\n                    }\n\n                    long long delta = compute_vertical_delta(\n                        swapChg.data(), 2 * N, totalFullCnt,\n                        pidSeen, pidDelta, pidStamp, touchedPid,\n                        sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                    );\n                    if (delta > bestDelta) {\n                        bestDelta = delta;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n\n            if (bi == -1) break;\n\n            int baseI = bi * N;\n            int baseJ = bj * N;\n            for (int c = 0; c < N; ++c) {\n                swapChg[2 * c] = {baseI + c, mat[baseI + c], mat[baseJ + c]};\n                swapChg[2 * c + 1] = {baseJ + c, mat[baseJ + c], mat[baseI + c]};\n            }\n\n            apply_vertical_changes(\n                mat, swapChg.data(), 2 * N, totalFullCnt, curScore,\n                pidSeen, pidDelta, pidStamp, touchedPid,\n                sidSeen, sidInc, sidDec, sidStamp, touchedSid\n            );\n            improved = true;\n        }\n\n        if (!improved) break;\n    }\n\n    return {curScore, mat};\n}\n\n// ---------------- main ----------------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gStart = chrono::steady_clock::now();\n\n    int Nin, M;\n    cin >> Nin >> M;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M * 2);\n\n    vector<int> charFreq(8, 0);\n\n    for (int i = 0; i < M; ++i) {\n        string s;\n        cin >> s;\n        auto it = mp.find(s);\n        if (it == mp.end()) {\n            int id = (int)pats.size();\n            mp.emplace(s, id);\n            pats.push_back(s);\n            wt.push_back(1);\n        } else {\n            wt[it->second]++;\n        }\n        for (char c : s) ++charFreq[c - 'A'];\n    }\n\n    int U = (int)pats.size();\n    pch.resize(U);\n    for (int i = 0; i < U; ++i) {\n        pch[i].resize(pats[i].size());\n        for (int j = 0; j < (int)pats[i].size(); ++j) {\n            pch[i][j] = (unsigned char)(pats[i][j] - 'A');\n        }\n    }\n\n    memset(pairW, 0, sizeof(pairW));\n    memset(triW, 0, sizeof(triW));\n    for (int sid = 0; sid < U; ++sid) {\n        const auto& s = pch[sid];\n        int k = (int)s.size();\n        for (int i = 0; i + 1 < k; ++i) pairW[s[i]][s[i + 1]] += wt[sid];\n        for (int i = 0; i + 2 < k; ++i) triW[s[i]][s[i + 1]][s[i + 2]] += wt[sid];\n    }\n\n    vector<long long> imp(U);\n    for (int i = 0; i < U; ++i) {\n        int L = (int)pats[i].size();\n        imp[i] = 1LL * wt[i] * L * L;\n    }\n    impOrder.resize(U);\n    iota(impOrder.begin(), impOrder.end(), 0);\n    sort(impOrder.begin(), impOrder.end(), [&](int a, int b) {\n        if (imp[a] != imp[b]) return imp[a] > imp[b];\n        return pats[a].size() > pats[b].size();\n    });\n\n    // Stage 1: row assembly\n    vector<string> rows = build_initial_rows(charFreq);\n\n    // Stage 2: exact graph\n    build_exact_graph();\n\n    // Stage 3: build diverse starts\n    vector<Matrix> starts;\n\n    {\n        vector<Matrix> ng = build_ngram_starts(rows);\n        for (auto& m : ng) starts.push_back(m);\n    }\n\n    starts.push_back(make_matrix_from_rows(rows, false, false));\n    starts.push_back(make_matrix_from_rows(rows, false, true));\n    starts.push_back(make_matrix_from_rows(rows, true, false));\n    starts.push_back(make_matrix_from_rows(rows, true, true));\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n    starts.push_back(make_constant_matrix(bestChar));\n    starts.push_back(make_random_freq_matrix(charFreq));\n\n    // soft refinement on starts\n    vector<StartResult> refined;\n    refined.reserve(starts.size());\n\n    long long softDeadline = 1700;\n    for (int i = 0; i < (int)starts.size(); ++i) {\n        if (elapsed_ms() > softDeadline) break;\n\n        vector<int> kinds, inertias;\n        if (elapsed_ms() < 1250) {\n            kinds = {0, 1, 2, 3};\n            inertias = {120, 60, 36, 20};\n        } else {\n            kinds = {0, 1, 2};\n            inertias = {100, 50, 28};\n        }\n\n        StartResult res = soft_refine(starts[i], kinds, inertias, softDeadline);\n        refined.push_back(res);\n    }\n\n    if (refined.empty()) {\n        vector<int> tmp;\n        refined.push_back({init_state(starts[0], tmp), starts[0]});\n    }\n\n    sort(refined.begin(), refined.end(), [&](const StartResult& a, const StartResult& b) {\n        return a.score > b.score;\n    });\n\n    StartResult globalBest = refined[0];\n\n    // exact hill-climb on top starts\n    long long hcEnd = 2580;\n    for (int i = 0; i < min<int>(2, refined.size()); ++i) {\n        if (elapsed_ms() > hcEnd) break;\n        int maxPass = (i == 0 ? 2 : 1);\n        StartResult res = exact_hillclimb(refined[i].mat, maxPass, hcEnd);\n        if (res.score > globalBest.score) globalBest = res;\n    }\n\n    // zero-cost structural polish: row shifts/swaps\n    if (elapsed_ms() < 2860) {\n        StartResult z = exact_row_optimize(globalBest.mat, 2860);\n        if (z.score >= globalBest.score) globalBest = z;\n    }\n\n    // transpose -> same polish -> transpose back\n    if (elapsed_ms() < 2940) {\n        Matrix t = transpose_matrix(globalBest.mat);\n        StartResult zt = exact_row_optimize(t, 2940);\n        zt.mat = transpose_matrix(zt.mat);\n        if (zt.score >= globalBest.score) globalBest = zt;\n    }\n\n    // final exact polish\n    if (elapsed_ms() < 2985) {\n        StartResult res = exact_hillclimb(globalBest.mat, 1, 2985);\n        if (res.score > globalBest.score) globalBest = res;\n    }\n\n    // output\n    for (int r = 0; r < N; ++r) {\n        string out(N, 'A');\n        for (int c = 0; c < N; ++c) out[c] = char('A' + globalBest.mat[r * N + c]);\n        cout << out << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\n\nstatic constexpr int INF_INT = 1e9;\nstatic constexpr ll INF_LL = (ll)4e18;\n\nstruct Task {\n    // type: 0=fixed cell, 1=horizontal segment, 2=vertical segment\n    int type;\n    int seg;\n    int cell;\n};\n\nstruct CandidateResult {\n    bool valid = false;\n    ll cost = INF_LL;\n    string path;\n};\n\nint N, si, sj;\nvector<string> gridc;\nvector<vector<int>> idg;\n\nint Rcnt, sId;\nvector<int> rr, cc, cellW;\nvector<vector<int>> nbrs;\n\nint Hcnt, Vcnt;\nvector<int> hid, vid;\nvector<vector<int>> cellsH, cellsV;\nvector<vector<pair<int,int>>> adjHFull, adjHRes; // (v, cell)\n\nint sH, sV;\nvector<char> activeH, activeV;\nvector<int> bestCellH, bestCellV;\nvector<int> distStart;\n\nvector<char> dijReady;\nvector<vector<int>> distCache, parentCache;\n\nchrono::steady_clock::time_point globalStart;\n\nll elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - globalStart\n    ).count();\n}\n\nchar dirChar(int a, int b) {\n    if (rr[b] == rr[a] - 1 && cc[b] == cc[a]) return 'U';\n    if (rr[b] == rr[a] + 1 && cc[b] == cc[a]) return 'D';\n    if (rr[b] == rr[a] && cc[b] == cc[a] - 1) return 'L';\n    if (rr[b] == rr[a] && cc[b] == cc[a] + 1) return 'R';\n    return '?';\n}\n\nvoid runDijkstra(int src, vector<int>& dist, vector<int>& parent) {\n    dist.assign(Rcnt, INF_INT);\n    parent.assign(Rcnt, -1);\n    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [d, u] = pq.top();\n        pq.pop();\n        if (d != dist[u]) continue;\n        for (int v : nbrs[u]) {\n            int nd = d + cellW[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                parent[v] = u;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\nvoid ensureDijkstra(int src) {\n    if (dijReady[src]) return;\n    dijReady[src] = true;\n    runDijkstra(src, distCache[src], parentCache[src]);\n}\n\npair<bool,ll> validateAndCost(const string& path) {\n    vector<char> covH(Hcnt, false), covV(Vcnt, false);\n    int cur = sId;\n    covH[hid[cur]] = true;\n    covV[vid[cur]] = true;\n    ll cost = 0;\n\n    for (char ch : path) {\n        int ni = rr[cur], nj = cc[cur];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return {false, 0};\n\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return {false, 0};\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return {false, 0};\n\n        cost += cellW[nxt];\n        cur = nxt;\n        covH[hid[cur]] = true;\n        covV[vid[cur]] = true;\n    }\n\n    if (cur != sId) return {false, 0};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        if (!covH[hid[cid]] && !covV[vid[cid]]) return {false, 0};\n    }\n    return {true, cost};\n}\n\nvoid hopcroftKarp(\n    const vector<char>& selH,\n    const vector<char>& selV,\n    const vector<vector<pair<int,int>>>& adj,\n    vector<int>& matchH,\n    vector<int>& matchV\n) {\n    matchH.assign(Hcnt, -1);\n    matchV.assign(Vcnt, -1);\n    vector<int> level(Hcnt, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(level.begin(), level.end(), -1);\n        bool found = false;\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) {\n                level[h] = 0;\n                q.push(h);\n            }\n        }\n        while (!q.empty()) {\n            int h = q.front(); q.pop();\n            for (auto [v, cid] : adj[h]) {\n                (void)cid;\n                if (!selV[v]) continue;\n                int h2 = matchV[v];\n                if (h2 == -1) {\n                    found = true;\n                } else if (level[h2] == -1) {\n                    level[h2] = level[h] + 1;\n                    q.push(h2);\n                }\n            }\n        }\n        return found;\n    };\n\n    function<bool(int)> dfs = [&](int h) -> bool {\n        for (auto [v, cid] : adj[h]) {\n            (void)cid;\n            if (!selV[v]) continue;\n            int h2 = matchV[v];\n            if (h2 == -1 || (level[h2] == level[h] + 1 && dfs(h2))) {\n                matchH[h] = v;\n                matchV[v] = h;\n                return true;\n            }\n        }\n        level[h] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) dfs(h);\n        }\n    }\n}\n\npair<vector<char>, vector<char>> buildCanonicalMVC() {\n    vector<int> matchH, matchV;\n    hopcroftKarp(activeH, activeV, adjHRes, matchH, matchV);\n\n    vector<char> visH(Hcnt, false), visV(Vcnt, false);\n    queue<int> q;\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h] && matchH[h] == -1) {\n            visH[h] = true;\n            q.push(h);\n        }\n    }\n\n    while (!q.empty()) {\n        int h = q.front(); q.pop();\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (matchH[h] == v) continue;\n            if (!visV[v]) {\n                visV[v] = true;\n                int h2 = matchV[v];\n                if (h2 != -1 && !visH[h2]) {\n                    visH[h2] = true;\n                    q.push(h2);\n                }\n            }\n        }\n    }\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !visH[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && visV[v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\npair<vector<char>, vector<char>> buildWeightedVC(\n    const vector<ll>& wH,\n    const vector<ll>& wV\n) {\n    int S = Hcnt + Vcnt;\n    int T = S + 1;\n    mf_graph<ll> mf(T + 1);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) mf.add_edge(S, h, wH[h]);\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) mf.add_edge(Hcnt + v, T, wV[v]);\n    }\n    for (int h = 0; h < Hcnt; h++) {\n        if (!activeH[h]) continue;\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (!activeV[v]) continue;\n            mf.add_edge(h, Hcnt + v, INF_LL / 8);\n        }\n    }\n\n    mf.flow(S, T);\n    auto reach = mf.min_cut(S);\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !reach[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && reach[Hcnt + v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\nvector<Task> compressTasksByCell(vector<Task> tasks) {\n    vector<vector<Task>> buckets(Rcnt);\n    for (auto &t : tasks) buckets[t.cell].push_back(t);\n\n    vector<Task> out;\n    out.reserve(tasks.size());\n    for (int c = 0; c < Rcnt; c++) {\n        if (buckets[c].empty()) continue;\n        if (buckets[c].size() >= 2) {\n            out.push_back({0, -1, c});\n        } else {\n            out.push_back(buckets[c][0]);\n        }\n    }\n    sort(out.begin(), out.end(), [&](const Task& a, const Task& b) {\n        if (a.cell != b.cell) return a.cell < b.cell;\n        if (a.type != b.type) return a.type < b.type;\n        return a.seg < b.seg;\n    });\n    return out;\n}\n\nvector<Task> buildTasksPaired(const vector<char>& selH, const vector<char>& selV) {\n    vector<int> matchH, matchV;\n    hopcroftKarp(selH, selV, adjHFull, matchH, matchV);\n\n    vector<Task> tasks;\n    for (int h = 0; h < Hcnt; h++) {\n        if (!selH[h]) continue;\n        if (matchH[h] != -1) {\n            int v = matchH[h];\n            int cid = -1;\n            for (auto [vv, ccid] : adjHFull[h]) {\n                if (vv == v) {\n                    cid = ccid;\n                    break;\n                }\n            }\n            if (cid != -1) tasks.push_back({0, -1, cid});\n        }\n    }\n    for (int h = 0; h < Hcnt; h++) {\n        if (selH[h] && matchH[h] == -1) tasks.push_back({1, h, bestCellH[h]});\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (selV[v] && matchV[v] == -1) tasks.push_back({2, v, bestCellV[v]});\n    }\n    return compressTasksByCell(tasks);\n}\n\nvector<Task> buildTasksNoPair(const vector<char>& selH, const vector<char>& selV) {\n    vector<Task> tasks;\n    for (int h = 0; h < Hcnt; h++) if (selH[h]) tasks.push_back({1, h, bestCellH[h]});\n    for (int v = 0; v < Vcnt; v++) if (selV[v]) tasks.push_back({2, v, bestCellV[v]});\n    return compressTasksByCell(tasks);\n}\n\nstring makeTaskSig(const vector<Task>& tasks) {\n    string s;\n    s.reserve(tasks.size() * 12);\n    for (auto &t : tasks) {\n        s += char('0' + t.type);\n        s += ':';\n        s += to_string(t.seg);\n        s += ':';\n        s += to_string(t.cell);\n        s += ';';\n    }\n    return s;\n}\n\nbool buildData(\n    const vector<Task>& tasks,\n    vector<int>& sourceCells,\n    vector<vector<ll>>& d0\n) {\n    if (elapsed_ms() > 2820) return false;\n    int M = (int)tasks.size() + 1;\n    sourceCells.assign(M, -1);\n    sourceCells[0] = sId;\n    for (int i = 0; i < (int)tasks.size(); i++) sourceCells[i + 1] = tasks[i].cell;\n\n    for (int i = 0; i < M; i++) ensureDijkstra(sourceCells[i]);\n\n    d0.assign(M, vector<ll>(M, 0));\n    for (int i = 0; i < M; i++) {\n        int ci = sourceCells[i];\n        for (int j = 0; j < M; j++) {\n            if (i == j) d0[i][j] = 0;\n            else d0[i][j] = (ll)distCache[ci][sourceCells[j]] + cellW[ci];\n        }\n    }\n    return true;\n}\n\nll routeCostMat(const vector<int>& route, const vector<vector<ll>>& d0) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) s += d0[route[i]][route[i + 1]];\n    return s;\n}\n\nll routeActualCost(const vector<int>& route, const vector<int>& sourceCells) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distCache[sourceCells[route[i]]][sourceCells[route[i + 1]]];\n    }\n    return s;\n}\n\nvector<int> routeNearestNeighbor(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    vector<int> route;\n    route.reserve(M + 2);\n    route.push_back(0);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    int cur = 0;\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        ll bestD = INF_LL;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeNearestSeed(const vector<vector<ll>>& d0, int first) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n    if (first < 1 || first > M) return routeNearestNeighbor(d0);\n\n    vector<int> route;\n    route.reserve(M + 2);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    used[first] = true;\n    route.push_back(0);\n    route.push_back(first);\n    int cur = first;\n\n    for (int step = 1; step < M; step++) {\n        int best = -1;\n        ll bestD = INF_LL;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeCheapestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    used[0] = true;\n\n    int first = 1;\n    ll bestFirst = INF_LL;\n    for (int p = 1; p <= M; p++) {\n        ll val = d0[0][p] + d0[p][0];\n        if (val < bestFirst) {\n            bestFirst = val;\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        ll bestInc = INF_LL;\n        int bestP = -1, bestPos = -1;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n                int a = route[pos], b = route[pos + 1];\n                ll inc = d0[a][p] + d0[p][b] - d0[a][b];\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestP = p;\n                    bestPos = pos;\n                }\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, bestP);\n        used[bestP] = true;\n    }\n    return route;\n}\n\nvector<int> routeFarthestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    int first = 1;\n    ll far = -1;\n    for (int p = 1; p <= M; p++) {\n        if (d0[0][p] > far) {\n            far = d0[0][p];\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        int pick = -1;\n        ll bestFar = -1;\n        for (int p = 1; p <= M; p++) if (!used[p]) {\n            ll mn = INF_LL;\n            for (int x : route) mn = min(mn, d0[x][p]);\n            if (mn > bestFar) {\n                bestFar = mn;\n                pick = p;\n            }\n        }\n\n        ll bestInc = INF_LL;\n        int bestPos = -1;\n        for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n            int a = route[pos], b = route[pos + 1];\n            ll inc = d0[a][pick] + d0[pick][b] - d0[a][b];\n            if (inc < bestInc) {\n                bestInc = inc;\n                bestPos = pos;\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, pick);\n        used[pick] = true;\n    }\n\n    return route;\n}\n\nvoid improve2opt(vector<int>& route, const vector<vector<ll>>& d0) {\n    int M = (int)route.size() - 2;\n    int maxPass = (M <= 35 ? 4 : M <= 70 ? 2 : 1);\n    int L = (int)route.size();\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool improved = false;\n        for (int i = 1; i + 2 < L; i++) {\n            for (int j = i + 1; j + 1 < L; j++) {\n                ll oldv = d0[route[i - 1]][route[i]] + d0[route[j]][route[j + 1]];\n                ll newv = d0[route[i - 1]][route[j]] + d0[route[i]][route[j + 1]];\n                if (newv < oldv) {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n        if (!improved || elapsed_ms() > 2750) break;\n    }\n}\n\nbool improveRelocateOnce(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    for (int i = 1; i + 1 < L; i++) {\n        int a = route[i - 1], x = route[i], b = route[i + 1];\n        for (int j = 0; j + 1 < L; j++) {\n            if (j == i || j == i - 1) continue;\n            int c = route[j], d = route[j + 1];\n            ll oldv = d0[a][x] + d0[x][b] + d0[c][d];\n            ll newv = d0[a][b] + d0[c][x] + d0[x][d];\n            if (newv < oldv) {\n                int val = route[i];\n                route.erase(route.begin() + i);\n                if (j < i) route.insert(route.begin() + (j + 1), val);\n                else route.insert(route.begin() + j, val);\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nbool improveSwapOnce(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    for (int i = 1; i + 1 < L; i++) {\n        for (int j = i + 1; j + 1 < L; j++) {\n            ll oldv, newv;\n            int x = route[i], y = route[j];\n            if (j == i + 1) {\n                int a = route[i - 1], d = route[j + 1];\n                oldv = d0[a][x] + d0[x][y] + d0[y][d];\n                newv = d0[a][y] + d0[y][x] + d0[x][d];\n            } else {\n                int a = route[i - 1], b = route[i + 1];\n                int c = route[j - 1], d = route[j + 1];\n                oldv = d0[a][x] + d0[x][b] + d0[c][y] + d0[y][d];\n                newv = d0[a][y] + d0[y][b] + d0[c][x] + d0[x][d];\n            }\n            if (newv < oldv) {\n                swap(route[i], route[j]);\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nvoid improveRoute(vector<int>& route, const vector<vector<ll>>& d0) {\n    int M = (int)route.size() - 2;\n    improve2opt(route, d0);\n\n    if (M <= 40 && elapsed_ms() < 2650) {\n        for (int iter = 0; iter < 6; iter++) {\n            bool imp = false;\n            if (improveRelocateOnce(route, d0)) {\n                imp = true;\n                improve2opt(route, d0);\n            }\n            if (improveSwapOnce(route, d0)) {\n                imp = true;\n                improve2opt(route, d0);\n            }\n            if (!imp || elapsed_ms() > 2750) break;\n        }\n    }\n}\n\nvector<int> exactRoute(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n    if (M == 1) return {0, 1, 0};\n\n    int S = 1 << M;\n    vector<vector<ll>> dp(S, vector<ll>(M, INF_LL));\n    vector<vector<short>> pre(S, vector<short>(M, -1));\n\n    for (int i = 0; i < M; i++) dp[1 << i][i] = d0[0][i + 1];\n\n    for (int mask = 1; mask < S; mask++) {\n        for (int i = 0; i < M; i++) {\n            if (!(mask & (1 << i))) continue;\n            ll cur = dp[mask][i];\n            if (cur >= INF_LL / 4) continue;\n            int rem = ((S - 1) ^ mask);\n            while (rem) {\n                int b = rem & -rem;\n                int j = __builtin_ctz(b);\n                int nmask = mask | b;\n                ll nd = cur + d0[i + 1][j + 1];\n                if (nd < dp[nmask][j]) {\n                    dp[nmask][j] = nd;\n                    pre[nmask][j] = (short)i;\n                }\n                rem ^= b;\n            }\n        }\n    }\n\n    int all = S - 1;\n    ll best = INF_LL;\n    int last = -1;\n    for (int i = 0; i < M; i++) {\n        ll val = dp[all][i] + d0[i + 1][0];\n        if (val < best) {\n            best = val;\n            last = i;\n        }\n    }\n\n    vector<int> ord;\n    int mask = all;\n    while (last != -1) {\n        ord.push_back(last + 1);\n        int pl = pre[mask][last];\n        mask ^= (1 << last);\n        last = pl;\n    }\n    reverse(ord.begin(), ord.end());\n\n    vector<int> route;\n    route.push_back(0);\n    for (int x : ord) route.push_back(x);\n    route.push_back(0);\n    return route;\n}\n\nvector<int> buildBestOrder(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    if (M <= 12 && elapsed_ms() < 2400) {\n        return exactRoute(d0);\n    }\n\n    vector<vector<int>> cands;\n    cands.push_back(routeCheapestInsertion(d0));\n    cands.push_back(routeNearestNeighbor(d0));\n    if (M <= 60) cands.push_back(routeFarthestInsertion(d0));\n\n    if (M >= 2 && M <= 70) {\n        int farIdx = 1;\n        ll farVal = -1;\n        for (int p = 1; p <= M; p++) {\n            if (d0[0][p] > farVal) {\n                farVal = d0[0][p];\n                farIdx = p;\n            }\n        }\n        cands.push_back(routeNearestSeed(d0, farIdx));\n    }\n\n    ll best = INF_LL;\n    vector<int> bestRoute;\n\n    for (auto route : cands) {\n        improveRoute(route, d0);\n        ll c = routeCostMat(route, d0);\n        if (c < best) {\n            best = c;\n            bestRoute = move(route);\n        }\n        if (elapsed_ms() > 2780) break;\n    }\n    return bestRoute;\n}\n\nbool refineTaskCells(vector<Task>& tasks, const vector<int>& route, const vector<int>& sourceCells) {\n    int M = (int)tasks.size();\n    vector<int> pos(M + 1, -1);\n    for (int i = 0; i < (int)route.size(); i++) pos[route[i]] = i;\n\n    bool changed = false;\n    for (int ti = 0; ti < M; ti++) {\n        if (tasks[ti].type == 0) continue;\n        int idx = ti + 1;\n        int p = pos[idx];\n        if (p <= 0 || p + 1 >= (int)route.size()) continue;\n\n        int prevCell = sourceCells[route[p - 1]];\n        int nextCell = sourceCells[route[p + 1]];\n        const vector<int>& candCells =\n            (tasks[ti].type == 1 ? cellsH[tasks[ti].seg] : cellsV[tasks[ti].seg]);\n\n        ll bestVal = INF_LL;\n        int bestCid = tasks[ti].cell;\n        for (int cid : candCells) {\n            ll val = (ll)distCache[prevCell][cid]\n                   + (ll)distCache[nextCell][cid]\n                   + cellW[nextCell] - cellW[cid];\n            if (val < bestVal) {\n                bestVal = val;\n                bestCid = cid;\n            } else if (val == bestVal) {\n                if (distStart[cid] < distStart[bestCid]) bestCid = cid;\n            }\n        }\n        if (bestCid != tasks[ti].cell) {\n            tasks[ti].cell = bestCid;\n            changed = true;\n        }\n    }\n    return changed;\n}\n\nstring reconstructPath(const vector<int>& route, const vector<int>& sourceCells) {\n    string out;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        int src = sourceCells[route[i]];\n        int dst = sourceCells[route[i + 1]];\n        if (src == dst) continue;\n\n        vector<int> rev;\n        int cur = dst;\n        while (cur != src) {\n            int p = parentCache[src][cur];\n            if (p == -1) return \"\";\n            rev.push_back(cur);\n            cur = p;\n        }\n        reverse(rev.begin(), rev.end());\n\n        int prev = src;\n        for (int x : rev) {\n            char c = dirChar(prev, x);\n            if (c == '?') return \"\";\n            out.push_back(c);\n            prev = x;\n        }\n    }\n    return out;\n}\n\nstring pruneOneLoop(const string& path) {\n    if (path.empty()) return path;\n\n    int L = (int)path.size();\n    vector<int> pos(L + 1);\n    pos[0] = sId;\n    int cur = sId;\n    for (int i = 0; i < L; i++) {\n        int ni = rr[cur], nj = cc[cur];\n        char ch = path[i];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return path;\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return path;\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return path;\n        cur = nxt;\n        pos[i + 1] = cur;\n    }\n\n    vector<int> cntH(Hcnt, 0), cntV(Vcnt, 0);\n    for (int x : pos) {\n        cntH[hid[x]]++;\n        cntV[vid[x]]++;\n    }\n\n    vector<int> last(Rcnt, -1);\n    vector<int> tmpH(Hcnt, 0), tmpV(Vcnt, 0);\n    vector<int> touchedH, touchedV;\n\n    for (int r = 0; r <= L; r++) {\n        int cell = pos[r];\n        int l = last[cell];\n        if (l != -1 && r > l) {\n            touchedH.clear();\n            touchedV.clear();\n            for (int k = l + 1; k <= r; k++) {\n                int c = pos[k];\n                int h = hid[c], v = vid[c];\n                if (tmpH[h]++ == 0) touchedH.push_back(h);\n                if (tmpV[v]++ == 0) touchedV.push_back(v);\n            }\n\n            bool ok = true;\n            for (int h : touchedH) {\n                if (cntH[h] - tmpH[h] == 0) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) {\n                for (int v : touchedV) {\n                    if (cntV[v] - tmpV[v] == 0) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n\n            for (int h : touchedH) tmpH[h] = 0;\n            for (int v : touchedV) tmpV[v] = 0;\n\n            if (ok) {\n                string res;\n                res.reserve(path.size() - (r - l));\n                res.append(path.begin(), path.begin() + l);\n                res.append(path.begin() + r, path.end());\n                return res;\n            }\n        }\n        last[cell] = r;\n    }\n    return path;\n}\n\nstring pruneLoops(string path) {\n    for (int pass = 0; pass < 2; pass++) {\n        if (elapsed_ms() > 2890) break;\n        string np = pruneOneLoop(path);\n        if (np.size() == path.size()) break;\n        auto [ok, c] = validateAndCost(np);\n        if (!ok) break;\n        path = move(np);\n    }\n    return path;\n}\n\nCandidateResult solveCandidate(vector<Task> tasks) {\n    CandidateResult res;\n    tasks = compressTasksByCell(tasks);\n\n    if ((int)tasks.size() > 90) return res;\n    if (elapsed_ms() > 2810) return res;\n\n    if (tasks.empty()) {\n        auto [ok, c] = validateAndCost(\"\");\n        if (ok) {\n            res.valid = true;\n            res.cost = c;\n            res.path = \"\";\n        }\n        return res;\n    }\n\n    vector<int> sourceCells;\n    vector<vector<ll>> d0;\n\n    if (!buildData(tasks, sourceCells, d0)) return res;\n    vector<int> route = buildBestOrder(d0);\n    ll bestRouteCost = routeActualCost(route, sourceCells);\n\n    if (elapsed_ms() < 2650) {\n        vector<Task> tasks2 = tasks;\n        if (refineTaskCells(tasks2, route, sourceCells)) {\n            tasks2 = compressTasksByCell(tasks2);\n            if ((int)tasks2.size() <= 90) {\n                vector<int> sourceCells2;\n                vector<vector<ll>> d02;\n                if (buildData(tasks2, sourceCells2, d02)) {\n                    auto route2 = buildBestOrder(d02);\n                    ll cost2 = routeActualCost(route2, sourceCells2);\n                    if (cost2 < bestRouteCost) {\n                        tasks = move(tasks2);\n                        sourceCells = move(sourceCells2);\n                        d0 = move(d02);\n                        route = move(route2);\n                        bestRouteCost = cost2;\n                    }\n                }\n            }\n        }\n    }\n\n    string path = reconstructPath(route, sourceCells);\n    auto [ok, c] = validateAndCost(path);\n    if (ok) {\n        res.valid = true;\n        res.cost = c;\n        res.path = move(path);\n    }\n    return res;\n}\n\nstring buildFallbackDFSRoute() {\n    vector<char> vis(Rcnt, false);\n    string out;\n\n    vector<int> it(Rcnt, 0);\n    vector<int> st;\n    st.push_back(sId);\n    vis[sId] = true;\n\n    while (!st.empty()) {\n        int u = st.back();\n        if (it[u] == (int)nbrs[u].size()) {\n            st.pop_back();\n            if (!st.empty()) {\n                int p = st.back();\n                out.push_back(dirChar(u, p));\n            }\n            continue;\n        }\n        int v = nbrs[u][it[u]++];\n        if (vis[v]) continue;\n        vis[v] = true;\n        out.push_back(dirChar(u, v));\n        st.push_back(v);\n    }\n    return out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    globalStart = chrono::steady_clock::now();\n\n    cin >> N >> si >> sj;\n    gridc.resize(N);\n    for (int i = 0; i < N; i++) cin >> gridc[i];\n\n    idg.assign(N, vector<int>(N, -1));\n    rr.clear();\n    cc.clear();\n    cellW.clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (gridc[i][j] != '#') {\n                idg[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                cellW.push_back(gridc[i][j] - '0');\n            }\n        }\n    }\n\n    Rcnt = (int)rr.size();\n    sId = idg[si][sj];\n\n    nbrs.assign(Rcnt, {});\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int i = rr[cid], j = cc[cid];\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) {\n                int nid = idg[ni][nj];\n                if (nid != -1) nbrs[cid].push_back(nid);\n            }\n        }\n    }\n    for (int u = 0; u < Rcnt; u++) {\n        sort(nbrs[u].begin(), nbrs[u].end(), [&](int a, int b) {\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    hid.assign(Rcnt, -1);\n    vid.assign(Rcnt, -1);\n    cellsH.clear();\n    cellsV.clear();\n\n    Hcnt = 0;\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (idg[i][j] == -1) {\n                j++;\n                continue;\n            }\n            int h = Hcnt++;\n            cellsH.push_back({});\n            while (j < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                hid[cid] = h;\n                cellsH[h].push_back(cid);\n                j++;\n            }\n        }\n    }\n\n    Vcnt = 0;\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (idg[i][j] == -1) {\n                i++;\n                continue;\n            }\n            int v = Vcnt++;\n            cellsV.push_back({});\n            while (i < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                vid[cid] = v;\n                cellsV[v].push_back(cid);\n                i++;\n            }\n        }\n    }\n\n    adjHFull.assign(Hcnt, {});\n    for (int cid = 0; cid < Rcnt; cid++) {\n        adjHFull[hid[cid]].push_back({vid[cid], cid});\n    }\n\n    dijReady.assign(Rcnt, false);\n    distCache.assign(Rcnt, {});\n    parentCache.assign(Rcnt, {});\n    ensureDijkstra(sId);\n    distStart = distCache[sId];\n\n    bestCellH.assign(Hcnt, -1);\n    bestCellV.assign(Vcnt, -1);\n\n    auto betterCell = [&](int a, int b) {\n        if (a == -1) return true;\n        if (distStart[b] != distStart[a]) return distStart[b] < distStart[a];\n        if (cellW[b] != cellW[a]) return cellW[b] < cellW[a];\n        if (rr[b] != rr[a]) return rr[b] < rr[a];\n        return cc[b] < cc[a];\n    };\n\n    for (int h = 0; h < Hcnt; h++) {\n        for (int cid : cellsH[h]) {\n            if (bestCellH[h] == -1 || betterCell(bestCellH[h], cid)) bestCellH[h] = cid;\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        for (int cid : cellsV[v]) {\n            if (bestCellV[v] == -1 || betterCell(bestCellV[v], cid)) bestCellV[v] = cid;\n        }\n    }\n\n    for (int h = 0; h < Hcnt; h++) {\n        sort(adjHFull[h].begin(), adjHFull[h].end(), [&](auto A, auto B) {\n            int a = A.second, b = B.second;\n            if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    sH = hid[sId];\n    sV = vid[sId];\n\n    activeH.assign(Hcnt, false);\n    activeV.assign(Vcnt, false);\n    adjHRes.assign(Hcnt, {});\n    bool anyResidual = false;\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int h = hid[cid], v = vid[cid];\n        if (h == sH || v == sV) continue; // already visible from start\n        activeH[h] = true;\n        activeV[v] = true;\n        adjHRes[h].push_back({v, cid});\n        anyResidual = true;\n    }\n\n    if (!anyResidual) {\n        cout << '\\n';\n        return 0;\n    }\n\n    vector<ll> segCostH(Hcnt, 0), segCostV(Vcnt, 0);\n    ll sumSeg = 0;\n    int cntSeg = 0;\n    for (int h = 0; h < Hcnt; h++) if (activeH[h]) {\n        segCostH[h] = distStart[bestCellH[h]];\n        sumSeg += segCostH[h];\n        cntSeg++;\n    }\n    for (int v = 0; v < Vcnt; v++) if (activeV[v]) {\n        segCostV[v] = distStart[bestCellV[v]];\n        sumSeg += segCostV[v];\n        cntSeg++;\n    }\n    ll avgSeg = max(1LL, cntSeg ? sumSeg / cntSeg : 1LL);\n\n    string bestPath = buildFallbackDFSRoute();\n    auto [fbok, fbcost] = validateAndCost(bestPath);\n    if (!fbok) {\n        bestPath = \"\";\n        fbcost = INF_LL;\n    }\n    ll bestCost = fbcost;\n\n    vector<pair<vector<char>, vector<char>>> covers;\n    unordered_set<string> seenCover;\n\n    auto addCover = [&](const vector<char>& selH, const vector<char>& selV) {\n        string sig;\n        sig.reserve(Hcnt + Vcnt);\n        for (int h = 0; h < Hcnt; h++) sig.push_back(selH[h] ? '1' : '0');\n        for (int v = 0; v < Vcnt; v++) sig.push_back(selV[v] ? '1' : '0');\n        if (seenCover.insert(sig).second) covers.push_back({selH, selV});\n    };\n\n    auto mvc = buildCanonicalMVC();\n    addCover(mvc.first, mvc.second);\n\n    ll base = sumSeg + 1;\n\n    vector<ll> wH1(Hcnt, 0), wV1(Vcnt, 0);\n    vector<ll> wH2(Hcnt, 0), wV2(Vcnt, 0);\n    vector<ll> wH3(Hcnt, 0), wV3(Vcnt, 0);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) {\n            wH1[h] = base + segCostH[h];     // cardinality-first\n            wH2[h] = 1 + segCostH[h];        // distance-first\n            wH3[h] = avgSeg + segCostH[h];   // middle\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) {\n            wV1[v] = base + segCostV[v];\n            wV2[v] = 1 + segCostV[v];\n            wV3[v] = avgSeg + segCostV[v];\n        }\n    }\n\n    auto cv1 = buildWeightedVC(wH1, wV1);\n    auto cv2 = buildWeightedVC(wH2, wV2);\n    auto cv3 = buildWeightedVC(wH3, wV3);\n    addCover(cv1.first, cv1.second);\n    addCover(cv2.first, cv2.second);\n    addCover(cv3.first, cv3.second);\n\n    {\n        vector<char> allH = activeH, allV(Vcnt, false);\n        addCover(allH, allV);\n    }\n    {\n        vector<char> allH(Hcnt, false), allV = activeV;\n        addCover(allH, allV);\n    }\n\n    vector<vector<Task>> candidates;\n    unordered_set<string> seenTask;\n\n    auto addTasks = [&](vector<Task> tasks) {\n        tasks = compressTasksByCell(tasks);\n        if ((int)tasks.size() > 90) return;\n        string sig = makeTaskSig(tasks);\n        if (seenTask.insert(sig).second) candidates.push_back(move(tasks));\n    };\n\n    for (int i = 0; i < (int)covers.size(); i++) {\n        addTasks(buildTasksPaired(covers[i].first, covers[i].second));\n        if (i < 2) {\n            auto np = buildTasksNoPair(covers[i].first, covers[i].second);\n            if ((int)np.size() <= 60) addTasks(move(np));\n        }\n    }\n\n    sort(candidates.begin(), candidates.end(), [&](const vector<Task>& A, const vector<Task>& B) {\n        if (A.size() != B.size()) return A.size() < B.size();\n        ll sA = 0, sB = 0;\n        for (auto &t : A) sA += distStart[t.cell];\n        for (auto &t : B) sB += distStart[t.cell];\n        return sA < sB;\n    });\n\n    for (auto &tasks : candidates) {\n        if (elapsed_ms() > 2770) break;\n        CandidateResult cr = solveCandidate(tasks);\n        if (cr.valid && cr.cost < bestCost) {\n            bestCost = cr.cost;\n            bestPath = move(cr.path);\n        }\n    }\n\n    if (!bestPath.empty() && elapsed_ms() < 2890) {\n        string pruned = pruneLoops(bestPath);\n        auto [okp, cp] = validateAndCost(pruned);\n        if (okp && cp < bestCost) {\n            bestCost = cp;\n            bestPath = move(pruned);\n        }\n    }\n\n    cout << bestPath << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int MAXN = 1000;\nstatic constexpr ll INF64 = (1LL << 62);\nstatic constexpr ll DUMMY_UTILITY = -4'000'000'000'000LL;\n\nstruct Observation {\n    int task;\n    int dur;\n};\n\nstruct Member {\n    int current_task = -1;\n    int start_day = -1;\n    vector<Observation> obs;\n    vector<int> est;\n    bool busy() const { return current_task != -1; }\n};\n\nstruct Solver {\n    int N, M, K, R;\n    vector<vector<int>> req;\n    vector<vector<int>> g;\n    vector<int> indeg_rem;\n    vector<int> state; // 0:not started, 1:in progress, 2:done\n    vector<Member> members;\n\n    vector<int> maxD;\n    vector<double> prior_cap;\n    vector<int> prior_int;\n    vector<double> rank_skill;\n    vector<double> easy_skill;\n\n    vector<int> desc_count;\n    vector<double> avg_proc;\n    vector<double> up_rank;\n    vector<double> base_priority_static;\n    vector<double> global_easy_dur;\n\n    int completed_tasks = 0;\n\n    static double expected_duration_from_w(double w) {\n        if (w <= 0.0) return 1.0;\n        static const double E[5] = {\n            1.0,\n            13.0 / 7.0,\n            17.0 / 7.0,\n            22.0 / 7.0,\n            4.0\n        };\n        if (w < 4.0) {\n            int a = (int)floor(w);\n            double f = w - a;\n            return E[a] * (1.0 - f) + E[a + 1] * f;\n        }\n        return w;\n    }\n\n    double predict_duration_with_skill(const vector<double>& skill, int task) const {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double diff = (double)req[task][k] - skill[k];\n            if (diff > 0) w += diff;\n        }\n        return expected_duration_from_w(w);\n    }\n\n    static pair<int,int> duration_interval(int t) {\n        if (t <= 1) return {0, 4};\n        return {max(1, t - 3), t + 3};\n    }\n\n    void read_input() {\n        cin >> N >> M >> K >> R;\n        req.assign(N, vector<int>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) cin >> req[i][k];\n        }\n        g.assign(N, {});\n        indeg_rem.assign(N, 0);\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            g[u].push_back(v);\n            indeg_rem[v]++;\n        }\n        state.assign(N, 0);\n        members.assign(M, Member{});\n    }\n\n    void preprocess() {\n        maxD.assign(K, 0);\n        vector<double> meanD(K, 0.0);\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                maxD[k] = max(maxD[k], req[i][k]);\n                meanD[k] += req[i][k];\n            }\n        }\n        for (int k = 0; k < K; k++) meanD[k] /= N;\n\n        prior_cap.assign(K, 0.0);\n        prior_int.assign(K, 0);\n        rank_skill.assign(K, 0.0);\n        easy_skill.assign(K, 0.0);\n\n        for (int k = 0; k < K; k++) {\n            double p = 1.6 * meanD[k];\n            p = min<double>(p, maxD[k]);\n            if (p < 0) p = 0;\n            prior_cap[k] = p;\n            prior_int[k] = (int)llround(p);\n            prior_int[k] = max(0, min(prior_int[k], maxD[k]));\n            rank_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.75);\n            easy_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.80);\n        }\n\n        for (int j = 0; j < M; j++) {\n            members[j].est = prior_int;\n        }\n\n        // Exact descendant counts with bitset.\n        vector<bitset<MAXN>> reach(N);\n        desc_count.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            bitset<MAXN> bs;\n            for (int to : g[i]) {\n                bs |= reach[to];\n                bs.set(to);\n            }\n            reach[i] = bs;\n            desc_count[i] = (int)bs.count();\n        }\n\n        avg_proc.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            avg_proc[i] = predict_duration_with_skill(rank_skill, i);\n        }\n\n        up_rank.assign(N, 0.0);\n        for (int i = N - 1; i >= 0; i--) {\n            double mx = 0.0;\n            for (int to : g[i]) mx = max(mx, up_rank[to]);\n            up_rank[i] = avg_proc[i] + mx;\n        }\n\n        base_priority_static.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            base_priority_static[i] = up_rank[i] + 0.03 * desc_count[i];\n        }\n\n        global_easy_dur.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            global_easy_dur[i] = predict_duration_with_skill(easy_skill, i);\n        }\n    }\n\n    void reestimate_member(int j) {\n        auto& mem = members[j];\n        int nobs = (int)mem.obs.size();\n        if (nobs == 0) {\n            mem.est = prior_int;\n            return;\n        }\n        if ((int)mem.est.size() != K) mem.est = prior_int;\n\n        vector<int> s = mem.est;\n        for (int k = 0; k < K; k++) {\n            s[k] = max(0, min(s[k], maxD[k]));\n        }\n\n        vector<int> task_id(nobs), L(nobs), U(nobs);\n        for (int i = 0; i < nobs; i++) {\n            task_id[i] = mem.obs[i].task;\n            auto [l, u] = duration_interval(mem.obs[i].dur);\n            L[i] = l;\n            U[i] = u;\n        }\n\n        vector<int> pred(nobs, 0);\n        for (int i = 0; i < nobs; i++) {\n            int t = task_id[i];\n            int w = 0;\n            for (int k = 0; k < K; k++) {\n                w += max(0, req[t][k] - s[k]);\n            }\n            pred[i] = w;\n        }\n\n        int passes = (nobs < 8 ? 3 : 2);\n        double reg = 10.0 / (nobs + 3.0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            for (int k = 0; k < K; k++) {\n                int old = s[k];\n                int lim = maxD[k];\n\n                vector<int> dk(nobs), oldPart(nobs);\n                for (int i = 0; i < nobs; i++) {\n                    int dkk = req[task_id[i]][k];\n                    dk[i] = dkk;\n                    oldPart[i] = max(0, dkk - old);\n                }\n\n                double bestObj = 1e100;\n                int bestX = old;\n\n                for (int x = 0; x <= lim; x++) {\n                    double obj = reg * (x - prior_int[k]) * (x - prior_int[k]);\n                    for (int i = 0; i < nobs; i++) {\n                        int w = pred[i] - oldPart[i] + max(0, dk[i] - x);\n                        if (w < L[i]) {\n                            double d = (double)(L[i] - w);\n                            obj += d * d;\n                        } else if (w > U[i]) {\n                            double d = (double)(w - U[i]);\n                            obj += d * d;\n                        }\n                    }\n                    if (obj < bestObj) {\n                        bestObj = obj;\n                        bestX = x;\n                    }\n                }\n\n                if (bestX != old) {\n                    for (int i = 0; i < nobs; i++) {\n                        pred[i] = pred[i] - oldPart[i] + max(0, dk[i] - bestX);\n                    }\n                    s[k] = bestX;\n                }\n            }\n        }\n\n        mem.est = s;\n    }\n\n    vector<int> hungarian_min(const vector<vector<ll>>& cost) {\n        int n = (int)cost.size();\n        int m = (int)cost[0].size();\n        // Requires n <= m\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF64);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF64;\n                for (int j = 1; j <= m; j++) {\n                    if (used[j]) continue;\n                    ll cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0 != 0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    vector<pair<int,int>> choose_assignments(int day) {\n        vector<int> free_members, ready_tasks;\n        for (int j = 0; j < M; j++) if (!members[j].busy()) free_members.push_back(j);\n        for (int i = 0; i < N; i++) if (state[i] == 0 && indeg_rem[i] == 0) ready_tasks.push_back(i);\n\n        if (free_members.empty() || ready_tasks.empty()) return {};\n\n        vector<vector<double>> eff_skill(M, vector<double>(K, 0.0));\n        for (int j = 0; j < M; j++) {\n            double conf = (double)members[j].obs.size() / (members[j].obs.size() + 5.0);\n            for (int k = 0; k < K; k++) {\n                eff_skill[j][k] = conf * members[j].est[k] + (1.0 - conf) * prior_cap[k];\n            }\n        }\n\n        vector<double> dynP(N, -1e100);\n        vector<pair<double,int>> order;\n        order.reserve(ready_tasks.size());\n\n        for (int task : ready_tasks) {\n            double unlock_bonus = 0.0;\n            for (int to : g[task]) {\n                if (state[to] == 0 && indeg_rem[to] == 1) {\n                    unlock_bonus += base_priority_static[to];\n                }\n            }\n            double p = base_priority_static[task] + 0.15 * unlock_bonus - 1e-4 * task;\n            dynP[task] = p;\n            order.push_back({p, task});\n        }\n\n        sort(order.begin(), order.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        auto raw_pred = [&](int member, int task) -> double {\n            return predict_duration_with_skill(eff_skill[member], task);\n        };\n\n        vector<char> used_member(M, false), used_task(N, false);\n        vector<pair<int,int>> res;\n\n        int urgent = 0;\n        if ((int)free_members.size() >= 2) {\n            urgent = min<int>((int)free_members.size(), (completed_tasks < 2 * M ? 2 : 3));\n        }\n\n        int ptr = 0;\n        while (urgent > 0 && ptr < (int)order.size()) {\n            int task = order[ptr++].second;\n            if (used_task[task]) continue;\n\n            double bestDur = 1e100;\n            int bestMember = -1;\n            for (int j : free_members) {\n                if (used_member[j]) continue;\n                double d = raw_pred(j, task);\n                if (d < bestDur - 1e-12 || (abs(d - bestDur) <= 1e-12 && j < bestMember)) {\n                    bestDur = d;\n                    bestMember = j;\n                }\n            }\n            if (bestMember == -1) break;\n\n            used_member[bestMember] = true;\n            used_task[task] = true;\n            res.push_back({bestMember, task});\n            urgent--;\n        }\n\n        vector<int> rem_members;\n        for (int j : free_members) if (!used_member[j]) rem_members.push_back(j);\n\n        vector<int> rem_tasks_order;\n        for (auto [p, t] : order) if (!used_task[t]) rem_tasks_order.push_back(t);\n\n        if (rem_members.empty() || rem_tasks_order.empty()) return res;\n\n        vector<int> cand;\n        vector<char> chosen(N, false);\n\n        if ((int)rem_tasks_order.size() <= 80) {\n            cand = rem_tasks_order;\n            for (int t : cand) chosen[t] = true;\n        } else {\n            const int TOP_PRIO = 50;\n            const int TOP_EASY = 25;\n\n            for (int i = 0; i < (int)rem_tasks_order.size() && (int)cand.size() < TOP_PRIO; i++) {\n                int t = rem_tasks_order[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            vector<int> easy = rem_tasks_order;\n            sort(easy.begin(), easy.end(), [&](int a, int b) {\n                if (global_easy_dur[a] != global_easy_dur[b]) return global_easy_dur[a] < global_easy_dur[b];\n                if (dynP[a] != dynP[b]) return dynP[a] > dynP[b];\n                return a < b;\n            });\n\n            for (int i = 0; i < (int)easy.size() && i < TOP_EASY; i++) {\n                int t = easy[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            int need = min<int>((int)rem_tasks_order.size(), max<int>((int)rem_members.size(), 20));\n            for (int t : rem_tasks_order) {\n                if ((int)cand.size() >= need) break;\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n        }\n\n        if (cand.empty()) return res;\n\n        int n = (int)rem_members.size();\n        int m = (int)cand.size() + n; // add dummy columns\n        vector<vector<ll>> util(n, vector<ll>(m, DUMMY_UTILITY));\n\n        for (int r = 0; r < n; r++) {\n            int member = rem_members[r];\n            int oc = (int)members[member].obs.size();\n            for (int c = 0; c < (int)cand.size(); c++) {\n                int task = cand[c];\n                double dur = raw_pred(member, task);\n\n                if (oc == 0) {\n                    if (completed_tasks < M) dur *= 2.2;\n                    else if (completed_tasks < 3 * M) dur *= 1.6;\n                } else if (oc == 1 && completed_tasks < 3 * M) {\n                    dur *= 1.2;\n                }\n\n                double u = dynP[task] * 1200.0 - dur * 800.0;\n                util[r][c] = llround(u);\n            }\n        }\n\n        ll maxU = DUMMY_UTILITY;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                maxU = max(maxU, util[i][j]);\n            }\n        }\n\n        vector<vector<ll>> cost(n, vector<ll>(m));\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                cost[i][j] = maxU - util[i][j];\n            }\n        }\n\n        vector<int> assign = hungarian_min(cost);\n        for (int r = 0; r < n; r++) {\n            int c = assign[r];\n            if (0 <= c && c < (int)cand.size()) {\n                res.push_back({rem_members[r], cand[c]});\n            }\n        }\n\n        return res;\n    }\n\n    void run() {\n        read_input();\n        preprocess();\n\n        for (int day = 1; ; day++) {\n            auto assignments = choose_assignments(day);\n\n            // Apply assignments locally before output.\n            for (auto [j, t] : assignments) {\n                members[j].current_task = t;\n                members[j].start_day = day;\n                state[t] = 1;\n            }\n\n            cout << assignments.size();\n            for (auto [j, t] : assignments) {\n                cout << ' ' << (j + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int ncomp;\n            if (!(cin >> ncomp)) return;\n            if (ncomp == -1) return;\n\n            vector<int> finished_members(ncomp);\n            for (int i = 0; i < ncomp; i++) {\n                cin >> finished_members[i];\n                --finished_members[i];\n            }\n\n            vector<int> completed_today_tasks;\n            completed_today_tasks.reserve(ncomp);\n\n            for (int j : finished_members) {\n                if (j < 0 || j >= M) continue;\n                if (!members[j].busy()) continue;\n\n                int task = members[j].current_task;\n                int dur = day - members[j].start_day + 1;\n\n                members[j].obs.push_back({task, dur});\n                members[j].current_task = -1;\n                members[j].start_day = -1;\n\n                if (0 <= task && task < N && state[task] == 1) {\n                    state[task] = 2;\n                    completed_today_tasks.push_back(task);\n                    completed_tasks++;\n                }\n\n                reestimate_member(j);\n            }\n\n            for (int task : completed_today_tasks) {\n                for (int to : g[task]) {\n                    if (state[to] == 0) {\n                        indeg_rem[to]--;\n                    }\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing u8 = unsigned char;\nusing u16 = uint16_t;\nusing u64 = uint64_t;\n\nstatic constexpr int N = 1000;\nstatic constexpr int M = 50;\nstatic constexpr int POINTS = 2 * N + 1; // 0..1999: pickups/deliveries, 2000: depot\nstatic constexpr int DEPOT = 2000;\nstatic constexpr int DEPOT_X = 400;\nstatic constexpr int DEPOT_Y = 400;\nstatic constexpr int MAX_ROUTE = 110;\nstatic constexpr int INF = 1e9;\n\nstatic u16 distMat[POINTS][POINTS];\nstatic int PX[POINTS], PY[POINTS];\n\nchrono::steady_clock::time_point g_start;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int pick_pid(int oid) { return oid << 1; }\ninline int del_pid(int oid) { return (oid << 1) | 1; }\n\nstruct Insertion {\n    int delta;\n    int gapP;\n    int gapD;\n    bool sameGap;\n};\n\nstruct Candidate {\n    int delta;\n    int oid;\n    Insertion ins;\n};\n\nstruct RouteContext {\n    int L = 0;\n    int E = 0;\n    int pid[MAX_ROUTE];\n    int edge[MAX_ROUTE];\n    int total = 0;\n};\n\nstruct Solution {\n    vector<int> route;       // point ids, includes depot at both ends\n    array<u8, N> sel{};\n    int cost = INF;\n};\n\nstatic inline u64 splitmix64(u64 x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\ninline int calc_cost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distMat[route[i]][route[i + 1]];\n    }\n    return s;\n}\n\ninline void build_context(const vector<int>& route, RouteContext& ctx) {\n    ctx.L = (int)route.size();\n    ctx.E = ctx.L - 1;\n    ctx.total = 0;\n    for (int i = 0; i < ctx.L; i++) ctx.pid[i] = route[i];\n    for (int i = 0; i < ctx.E; i++) {\n        ctx.edge[i] = distMat[ctx.pid[i]][ctx.pid[i + 1]];\n        ctx.total += ctx.edge[i];\n    }\n}\n\ninline Insertion find_best_insertion(const RouteContext& ctx, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n    const u16* Dp = distMat[p];\n    const u16* Dd = distMat[d];\n    const int pd = Dp[d];\n\n    int delCost[MAX_ROUTE];\n    int suffMin[MAX_ROUTE];\n    int suffArg[MAX_ROUTE];\n\n    for (int j = 0; j < ctx.E; j++) {\n        const int u = ctx.pid[j];\n        const int v = ctx.pid[j + 1];\n        delCost[j] = (int)Dd[u] + (int)Dd[v] - ctx.edge[j];\n    }\n\n    suffMin[ctx.E] = INF;\n    suffArg[ctx.E] = -1;\n    for (int j = ctx.E - 1; j >= 0; j--) {\n        if (delCost[j] <= suffMin[j + 1]) {\n            suffMin[j] = delCost[j];\n            suffArg[j] = j;\n        } else {\n            suffMin[j] = suffMin[j + 1];\n            suffArg[j] = suffArg[j + 1];\n        }\n    }\n\n    Insertion best{INF, -1, -1, true};\n\n    for (int i = 0; i < ctx.E; i++) {\n        const int u = ctx.pid[i];\n        const int v = ctx.pid[i + 1];\n\n        int same = (int)Dp[u] + pd + (int)Dd[v] - ctx.edge[i];\n        if (same < best.delta) {\n            best = Insertion{same, i, i, true};\n        }\n\n        if (i + 1 < ctx.E) {\n            int pickCost = (int)Dp[u] + (int)Dp[v] - ctx.edge[i];\n            int later = pickCost + suffMin[i + 1];\n            if (later < best.delta) {\n                best = Insertion{later, i, suffArg[i + 1], false};\n            }\n        }\n    }\n\n    return best;\n}\n\ninline vector<int> apply_insertion(const vector<int>& route, int oid, const Insertion& ins) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n\n    vector<int> res;\n    res.reserve(route.size() + 2);\n\n    for (int i = 0; i < (int)route.size(); i++) {\n        res.push_back(route[i]);\n        if (i == ins.gapP) {\n            res.push_back(p);\n            if (ins.sameGap) res.push_back(d);\n        }\n        if (!ins.sameGap && i == ins.gapD) {\n            res.push_back(d);\n        }\n    }\n    return res;\n}\n\ninline vector<int> remove_order_from_route(const vector<int>& route, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n    vector<int> res;\n    res.reserve(route.size() - 2);\n    for (int pid : route) {\n        if (pid != p && pid != d) res.push_back(pid);\n    }\n    return res;\n}\n\ninline vector<int> filter_route_without(const vector<int>& route, const array<u8, N>& removed) {\n    vector<int> res;\n    res.reserve(route.size());\n    for (int pid : route) {\n        if (pid == DEPOT) {\n            res.push_back(pid);\n        } else {\n            int oid = pid >> 1;\n            if (!removed[oid]) res.push_back(pid);\n        }\n    }\n    return res;\n}\n\ninline vector<int> selected_ids_from_route(const vector<int>& route) {\n    vector<int> ids;\n    ids.reserve(M);\n    for (int pid : route) {\n        if (pid != DEPOT && (pid & 1) == 0) ids.push_back(pid >> 1);\n    }\n    return ids;\n}\n\ninline void add_candidate(vector<Candidate>& bests, const Candidate& c, int K) {\n    int pos = 0;\n    while (pos < (int)bests.size() && bests[pos].delta <= c.delta) ++pos;\n    if (pos >= K) return;\n    bests.insert(bests.begin() + pos, c);\n    if ((int)bests.size() > K) bests.pop_back();\n}\n\ninline int pick_rcl_index(int sz, mt19937& rng) {\n    if (sz <= 1) return 0;\n    static const int W[12] = {32, 20, 14, 10, 8, 6, 4, 3, 2, 1, 1, 1};\n    int sum = 0;\n    for (int i = 0; i < sz; i++) sum += W[i];\n    int r = (int)(rng() % sum);\n    for (int i = 0; i < sz; i++) {\n        if (r < W[i]) return i;\n        r -= W[i];\n    }\n    return sz - 1;\n}\n\nSolution construct_solution(int seedOid, int rclK, mt19937& rng) {\n    Solution sol;\n    sol.route = {DEPOT, DEPOT};\n    sol.sel.fill(0);\n    sol.cost = 0;\n    int cnt = 0;\n\n    if (seedOid != -1) {\n        int p = pick_pid(seedOid);\n        int d = del_pid(seedOid);\n        sol.route = {DEPOT, p, d, DEPOT};\n        sol.sel[seedOid] = 1;\n        sol.cost = distMat[DEPOT][p] + distMat[p][d] + distMat[d][DEPOT];\n        cnt = 1;\n    }\n\n    for (; cnt < M; cnt++) {\n        RouteContext ctx;\n        build_context(sol.route, ctx);\n\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n    }\n\n    return sol;\n}\n\ninline void compute_positions(const vector<int>& route, array<int, N>& posP, array<int, N>& posD) {\n    posP.fill(-1);\n    posD.fill(-1);\n    for (int i = 0; i < (int)route.size(); i++) {\n        int pid = route[i];\n        if (pid == DEPOT) continue;\n        int oid = pid >> 1;\n        if ((pid & 1) == 0) posP[oid] = i;\n        else posD[oid] = i;\n    }\n}\n\ninline int exact_removal_saving(const vector<int>& route, int ip, int id) {\n    if (ip > id) swap(ip, id);\n    if (id == ip + 1) {\n        int a = route[ip - 1], b = route[ip], c = route[id], d = route[id + 1];\n        return (int)distMat[a][b] + (int)distMat[b][c] + (int)distMat[c][d] - (int)distMat[a][d];\n    } else {\n        int a = route[ip - 1], b = route[ip], c = route[ip + 1];\n        int e = route[id - 1], f = route[id], g = route[id + 1];\n        return ((int)distMat[a][b] + (int)distMat[b][c] - (int)distMat[a][c]) +\n               ((int)distMat[e][f] + (int)distMat[f][g] - (int)distMat[e][g]);\n    }\n}\n\nbool best_pair_reinsert_once(Solution& sol, double deadline) {\n    vector<int> ids = selected_ids_from_route(sol.route);\n\n    int bestCost = sol.cost;\n    int bestOid = -1;\n    Insertion bestIns{};\n    vector<int> bestBase;\n\n    for (int t = 0; t < (int)ids.size(); t++) {\n        if ((t & 7) == 0 && elapsed_sec() > deadline) break;\n        int oid = ids[t];\n        vector<int> base = remove_order_from_route(sol.route, oid);\n        RouteContext ctx;\n        build_context(base, ctx);\n        Insertion ins = find_best_insertion(ctx, oid);\n        int nc = ctx.total + ins.delta;\n        if (nc < bestCost) {\n            bestCost = nc;\n            bestOid = oid;\n            bestIns = ins;\n            bestBase = move(base);\n        }\n    }\n\n    if (bestOid == -1) return false;\n    sol.route = apply_insertion(bestBase, bestOid, bestIns);\n    sol.cost = bestCost;\n    return true;\n}\n\nbool best_single_replace_once(Solution& sol, double deadline) {\n    vector<int> selIds = selected_ids_from_route(sol.route);\n\n    int bestCost = sol.cost;\n    int remOid = -1, addOid = -1;\n    Insertion bestIns{};\n    vector<int> bestBase;\n\n    for (int si = 0; si < (int)selIds.size(); si++) {\n        if ((si & 3) == 0 && elapsed_sec() > deadline) break;\n\n        int x = selIds[si];\n        vector<int> base = remove_order_from_route(sol.route, x);\n        RouteContext ctx;\n        build_context(base, ctx);\n\n        int localBestCost = INF;\n        int bestY = -1;\n        Insertion localIns{};\n\n        for (int y = 0; y < N; y++) {\n            if (sol.sel[y]) continue;\n            Insertion ins = find_best_insertion(ctx, y);\n            int c = ctx.total + ins.delta;\n            if (c < localBestCost) {\n                localBestCost = c;\n                bestY = y;\n                localIns = ins;\n            }\n        }\n\n        if (localBestCost < bestCost) {\n            bestCost = localBestCost;\n            remOid = x;\n            addOid = bestY;\n            bestIns = localIns;\n            bestBase = move(base);\n        }\n    }\n\n    if (remOid == -1) return false;\n\n    sol.sel[remOid] = 0;\n    sol.sel[addOid] = 1;\n    sol.route = apply_insertion(bestBase, addOid, bestIns);\n    sol.cost = bestCost;\n    return true;\n}\n\nvoid local_opt(Solution& sol, double deadline, int maxReplace) {\n    int rep = 0;\n    while (elapsed_sec() < deadline) {\n        bool any = false;\n\n        while (elapsed_sec() < deadline && best_pair_reinsert_once(sol, deadline)) {\n            any = true;\n        }\n\n        if (rep < maxReplace && elapsed_sec() < deadline && best_single_replace_once(sol, deadline)) {\n            any = true;\n            rep++;\n            continue;\n        }\n\n        if (!any) break;\n    }\n}\n\nvector<int> choose_removals(const Solution& sol, int mode, int K, mt19937& rng) {\n    K = min(K, M);\n    vector<int> selIds = selected_ids_from_route(sol.route);\n\n    vector<int> res;\n    res.reserve(K);\n    array<u8, N> used{};\n    used.fill(0);\n\n    auto add_oid = [&](int oid) {\n        if (!used[oid]) {\n            used[oid] = 1;\n            res.push_back(oid);\n        }\n    };\n\n    if (mode == 0) {\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int i = 0; i < K; i++) add_oid(selIds[i]);\n    } else if (mode == 1) {\n        array<int, N> posP, posD;\n        compute_positions(sol.route, posP, posD);\n        vector<pair<int, int>> sav;\n        sav.reserve(M);\n        for (int oid : selIds) {\n            int s = exact_removal_saving(sol.route, posP[oid], posD[oid]);\n            sav.push_back({s, oid});\n        }\n        sort(sav.rbegin(), sav.rend());\n        for (int i = 0; i < K; i++) add_oid(sav[i].second);\n    } else if (mode == 2) {\n        int L = (int)sol.route.size();\n        int st = 1 + (int)(rng() % (L - 2));\n        int span = min(L - 2, st + 2 * K + 6);\n        for (int i = st; i <= span && (int)res.size() < K; i++) {\n            int pid = sol.route[i];\n            if (pid != DEPOT) add_oid(pid >> 1);\n        }\n        if ((int)res.size() < K) {\n            shuffle(selIds.begin(), selIds.end(), rng);\n            for (int oid : selIds) {\n                if ((int)res.size() >= K) break;\n                add_oid(oid);\n            }\n        }\n    } else if (mode == 3) {\n        int base = selIds[(int)(rng() % selIds.size())];\n        int bp = pick_pid(base), bd = del_pid(base);\n        vector<pair<int, int>> sim;\n        sim.reserve(M);\n        for (int oid : selIds) {\n            int s = (int)distMat[bp][pick_pid(oid)] + (int)distMat[bd][del_pid(oid)];\n            s += (int)(rng() % 50); // noise\n            sim.push_back({s, oid});\n        }\n        sort(sim.begin(), sim.end());\n        for (int i = 0; i < K; i++) add_oid(sim[i].second);\n    } else {\n        // mixed: half worst, half shaw/random\n        array<int, N> posP, posD;\n        compute_positions(sol.route, posP, posD);\n        vector<pair<int, int>> sav;\n        sav.reserve(M);\n        for (int oid : selIds) {\n            int s = exact_removal_saving(sol.route, posP[oid], posD[oid]);\n            sav.push_back({s, oid});\n        }\n        sort(sav.rbegin(), sav.rend());\n        int takeW = max(1, K / 2);\n        for (int i = 0; i < takeW; i++) add_oid(sav[i].second);\n\n        int base = selIds[(int)(rng() % selIds.size())];\n        int bp = pick_pid(base), bd = del_pid(base);\n        vector<pair<int, int>> sim;\n        sim.reserve(M);\n        for (int oid : selIds) {\n            int s = (int)distMat[bp][pick_pid(oid)] + (int)distMat[bd][del_pid(oid)];\n            s += (int)(rng() % 50);\n            sim.push_back({s, oid});\n        }\n        sort(sim.begin(), sim.end());\n        for (auto& [_, oid] : sim) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int oid : selIds) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n    }\n\n    return res;\n}\n\nSolution destroy_repair(const Solution& base, int mode, int K, int rclK, bool forbidRemoved, mt19937& rng) {\n    vector<int> rem = choose_removals(base, mode, K, rng);\n\n    Solution sol;\n    sol.sel = base.sel;\n\n    array<u8, N> removed{};\n    removed.fill(0);\n    array<u8, N> banned{};\n    banned.fill(0);\n\n    for (int oid : rem) {\n        removed[oid] = 1;\n        if (forbidRemoved) banned[oid] = 1;\n        sol.sel[oid] = 0;\n    }\n\n    sol.route = filter_route_without(base.route, removed);\n    RouteContext ctx;\n    build_context(sol.route, ctx);\n    sol.cost = ctx.total;\n\n    int cnt = M - (int)rem.size();\n    while (cnt < M) {\n        build_context(sol.route, ctx);\n\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            if (banned[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        if (bests.empty()) {\n            for (int oid = 0; oid < N; oid++) banned[oid] = 0;\n            for (int oid = 0; oid < N; oid++) {\n                if (sol.sel[oid]) continue;\n                Insertion ins = find_best_insertion(ctx, oid);\n                add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n            }\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n        cnt++;\n    }\n\n    return sol;\n}\n\ninline double rand01(mt19937& rng) {\n    return double(rng()) * (1.0 / 4294967296.0);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    u64 h = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        PX[pick_pid(i)] = a;\n        PY[pick_pid(i)] = b;\n        PX[del_pid(i)] = c;\n        PY[del_pid(i)] = d;\n\n        h = splitmix64(h ^ (u64)(a + 1009 * b + 9176 * c + 65537 * d + i * 1315423911u));\n    }\n    PX[DEPOT] = DEPOT_X;\n    PY[DEPOT] = DEPOT_Y;\n\n    g_start = chrono::steady_clock::now();\n\n    for (int i = 0; i < POINTS; i++) {\n        for (int j = 0; j < POINTS; j++) {\n            distMat[i][j] = (u16)(abs(PX[i] - PX[j]) + abs(PY[i] - PY[j]));\n        }\n    }\n\n    mt19937 rng((uint32_t)(h ^ (h >> 32)));\n\n    vector<pair<int, int>> centerRank;\n    centerRank.reserve(N);\n    for (int oid = 0; oid < N; oid++) {\n        int p = pick_pid(oid), d = del_pid(oid);\n        int sc = (int)distMat[DEPOT][p] + (int)distMat[p][d] + (int)distMat[d][DEPOT];\n        centerRank.push_back({sc, oid});\n    }\n    sort(centerRank.begin(), centerRank.end());\n\n    vector<int> seedPool;\n    for (int i = 0; i < min(250, N); i++) seedPool.push_back(centerRank[i].second);\n\n    const double INIT_DEADLINE = 0.55;\n    const double SEARCH_DEADLINE = 1.88;\n    const double FINAL_DEADLINE = 1.97;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto update_best = [&](Solution&& sol) {\n        if (!hasBest || sol.cost < best.cost) {\n            best = move(sol);\n            hasBest = true;\n        }\n    };\n\n    // Initial deterministic constructions\n    {\n        Solution sol = construct_solution(-1, 1, rng);\n        local_opt(sol, INIT_DEADLINE, 1);\n        update_best(move(sol));\n    }\n\n    for (int i = 0; i < 4 && elapsed_sec() < INIT_DEADLINE; i++) {\n        Solution sol = construct_solution(seedPool[i], 1, rng);\n        local_opt(sol, INIT_DEADLINE, 1);\n        update_best(move(sol));\n    }\n\n    // Randomized multistarts\n    while (elapsed_sec() < INIT_DEADLINE) {\n        int seed = ((rng() & 3) == 0 ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 120))]);\n        int rcl = 5 + (int)(rng() % 6); // 5..10\n        Solution sol = construct_solution(seed, rcl, rng);\n        if ((rng() & 1) == 0) local_opt(sol, INIT_DEADLINE, 0);\n        update_best(move(sol));\n    }\n\n    Solution current = best;\n\n    int iter = 0;\n    int stagn = 0;\n\n    while (elapsed_sec() < SEARCH_DEADLINE) {\n        if ((iter % 10) == 0) {\n            local_opt(current, SEARCH_DEADLINE, 0);\n            if (current.cost < best.cost) best = current;\n        }\n\n        double progress = max(0.0, min(1.0, (elapsed_sec() - INIT_DEADLINE) / (SEARCH_DEADLINE - INIT_DEADLINE)));\n        double temp = 50.0 * pow(2.0 / 50.0, progress);\n\n        int mode = (int)(rng() % 5);\n        int K = 3 + (int)(rng() % 6); // 3..8\n        if (stagn >= 10) K += 2;\n        if (stagn >= 20) K += 2;\n        if (K > 12) K = 12;\n\n        int rcl = 4 + (int)(rng() % 6); // 4..9\n        bool forbidRemoved = ((rng() & 3) != 0); // 75% of the time truly change subset\n\n        Solution cand = destroy_repair(current, mode, K, rcl, forbidRemoved, rng);\n\n        // Quick intensification\n        best_pair_reinsert_once(cand, SEARCH_DEADLINE);\n        if ((rng() % 6) == 0) best_single_replace_once(cand, SEARCH_DEADLINE);\n\n        if (cand.cost < best.cost) {\n            best = cand;\n            local_opt(best, SEARCH_DEADLINE, 1);\n            if (best.cost < cand.cost) cand = best;\n            stagn = 0;\n        } else {\n            stagn++;\n        }\n\n        int diff = cand.cost - current.cost;\n        bool accept = false;\n        if (diff <= 0) {\n            accept = true;\n        } else {\n            double prob = exp(-double(diff) / temp);\n            if (rand01(rng) < prob) accept = true;\n        }\n\n        if (accept) current = move(cand);\n\n        // If too stagnant, restart around best or from scratch.\n        if (stagn >= 30 && elapsed_sec() < 1.70) {\n            if (rng() & 1) {\n                current = best;\n            } else {\n                int seed = ((rng() & 1) ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 150))]);\n                current = construct_solution(seed, 8, rng);\n                best_pair_reinsert_once(current, SEARCH_DEADLINE);\n            }\n            stagn = 0;\n        }\n\n        iter++;\n    }\n\n    local_opt(best, FINAL_DEADLINE, 8);\n\n    vector<int> ids = selected_ids_from_route(best.route);\n\n    cout << ids.size();\n    for (int oid : ids) cout << ' ' << (oid + 1);\n    cout << '\\n';\n\n    cout << best.route.size();\n    for (int pid : best.route) {\n        cout << ' ' << PX[pid] << ' ' << PY[pid];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p; // negative size for roots\n\n    DSU() {}\n    DSU(int n) : p(n, -1) {}\n\n    int leader(int x) {\n        if (p[x] < 0) return x;\n        return p[x] = leader(p[x]);\n    }\n\n    bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (-p[a] < -p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        return true;\n    }\n};\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nstatic double clamp01(double x) {\n    if (x < 0.0) return 0.0;\n    if (x > 1.0) return 1.0;\n    return x;\n}\n\n// Approximate E[max(path edge lengths)] / mx for the path in the future-MST,\n// assuming each edge length is an independent continuous uniform on [d, 3d].\n// This is used only as a small correction over the robust base threshold.\nstatic double expected_bottleneck_factor(const vector<int>& pathd, int mx) {\n    if (pathd.empty() || mx <= 0) return 2.0;\n\n    // Only edges with 3d > mx can affect the expectation above mx.\n    vector<int> rel;\n    rel.reserve(pathd.size());\n    for (int d : pathd) {\n        if (3 * d > mx) rel.push_back(d);\n    }\n\n    // E[max]/mx = 1 + integral_{x=1..3} P(max >= mx*x) dx\n    // Use Simpson's rule. This is stable enough and cheap.\n    constexpr int SEG = 16; // must be even\n    const double h = 2.0 / SEG;\n\n    auto tail_prob = [&](double x) -> double {\n        double t = mx * x;\n        double prod = 1.0; // product of CDFs\n\n        for (int d : rel) {\n            if (t <= d) {\n                // This edge is always >= t, so max >= t with prob 1.\n                return 1.0;\n            }\n            if (t >= 3.0 * d) {\n                continue; // CDF = 1\n            }\n            prod *= (t - d) / (2.0 * d);\n            if (prod < 1e-15) return 1.0;\n        }\n\n        double ret = 1.0 - prod;\n        if (ret < 0.0) ret = 0.0;\n        if (ret > 1.0) ret = 1.0;\n        return ret;\n    };\n\n    double sum = 0.0;\n    for (int s = 0; s <= SEG; s++) {\n        double x = 1.0 + h * s;\n        int coef = (s == 0 || s == SEG ? 1 : (s & 1 ? 4 : 2));\n        sum += coef * tail_prob(x);\n    }\n    double integral = h * sum / 3.0;\n    double ans = 1.0 + integral;\n\n    if (ans < 2.0) ans = 2.0; // one-edge lower baseline\n    if (ans > 3.0) ans = 3.0;\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> xs[i] >> ys[i];\n    }\n\n    vector<int> U(M), V(M), D(M);\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n        long long dx = xs[U[i]] - xs[V[i]];\n        long long dy = ys[U[i]] - ys[V[i]];\n        D[i] = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n    }\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    DSU adopted(N);\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        // Already connected by adopted edges => this edge is surely unnecessary.\n        if (!adopted.same(u, v)) {\n            // Compress adopted components.\n            vector<int> root_id(N, -1), cid(N, -1);\n            int C = 0;\n            for (int x = 0; x < N; x++) {\n                int r = adopted.leader(x);\n                if (root_id[r] == -1) root_id[r] = C++;\n                cid[x] = root_id[r];\n            }\n\n            int cu = cid[u], cv = cid[v];\n\n            // Build future-only MST on current components using d as surrogate weight.\n            DSU uf2(C);\n            vector<vector<pair<int,int>>> tree(C); // (to, d)\n            int used = 0;\n            int useful_edges = 0;\n\n            for (int e : ord) {\n                if (e <= i) continue; // future only\n\n                int a = cid[U[e]];\n                int b = cid[V[e]];\n                if (a == b) continue;\n\n                useful_edges++;\n                if (uf2.merge(a, b)) {\n                    tree[a].push_back({b, D[e]});\n                    tree[b].push_back({a, D[e]});\n                    used++;\n                }\n            }\n\n            // If future edges alone cannot connect the current components,\n            // this edge is mandatory.\n            if (used < C - 1) {\n                ans = 1;\n            } else {\n                // Find the path between cu and cv in the future-only MST.\n                vector<int> parent(C, -1), pw(C, 0);\n                queue<int> q;\n                parent[cu] = cu;\n                q.push(cu);\n\n                while (!q.empty() && parent[cv] == -1) {\n                    int x = q.front();\n                    q.pop();\n                    for (auto [to, w] : tree[x]) {\n                        if (parent[to] != -1) continue;\n                        parent[to] = x;\n                        pw[to] = w;\n                        q.push(to);\n                    }\n                }\n\n                vector<int> pathd;\n                int mx = 0;\n                for (int cur = cv; cur != cu; cur = parent[cur]) {\n                    pathd.push_back(pw[cur]);\n                    mx = max(mx, pw[cur]);\n                }\n\n                // Base threshold from the first solution:\n                // denser future graph => more selective,\n                // sparser future graph => more conservative.\n                double density = (C <= 1 ? 10.0 : (double)useful_edges / (double)(C - 1));\n                double t = clamp01((density - 1.0) / 4.0);\n                double lambda_base = 2.05 - 0.45 * t; // [about 1.60, 2.05]\n\n                // Light correction from the expected realized bottleneck on this MST path.\n                // Important: use only as a small adjustment, not as the main rule.\n                double beta = expected_bottleneck_factor(pathd, mx); // in [2,3]\n                double lambda = lambda_base + 0.25 * (beta - 2.0);\n\n                // Small late-stage safety bump when alternatives are scarce.\n                double progress = (double)i / (double)(M - 1);\n                lambda += 0.04 * progress * (1.0 - t);\n\n                if (lambda < 1.55) lambda = 1.55;\n                if (lambda > 2.25) lambda = 2.25;\n\n                ans = ((double)l <= lambda * (double)mx + 1e-9) ? 1 : 0;\n            }\n        } else {\n            ans = 0;\n        }\n\n        cout << ans << '\\n' << flush;\n        if (ans) adopted.merge(u, v);\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int S = 30;\nstatic constexpr int MAX_TURN = 300;\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar moveChar[4] = {'U', 'D', 'L', 'R'};\n\nstruct Task {\n    int wr, wc;\n    int sr, sc;\n    char act;\n};\n\nstruct Door {\n    int wr, wc;\n    int sr, sc;\n    char act;\n};\n\nstruct Room {\n    int r1, r2, c1, c2;\n    int br, bc;\n    int centerR, centerC;\n    array<Door, 2> doors;\n    vector<Task> tasks;\n\n    bool inside(int r, int c) const {\n        return r1 <= r && r <= r2 && c1 <= c && c <= c2;\n    }\n    int area() const {\n        return (r2 - r1 + 1) * (c2 - c1 + 1);\n    }\n};\n\nstruct BFSRes {\n    int dist[S][S];\n    char first[S][S];\n    BFSRes() {\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < S; j++) {\n                dist[i][j] = -1;\n                first[i][j] = 0;\n            }\n        }\n    }\n};\n\nstruct RoomEval {\n    double aggressiveScore = -1e100;\n    double safeScore = -1e100;\n    int insidePets = 0;\n    int insideDogs = 0;\n    int expandedPets = 0;\n    int nearDoorPets = 0;\n    int nearDoorDogs = 0;\n    int sumBest = 0;\n    int tasks = 0;\n};\n\nint N, M;\nvector<pair<int,int>> petsPos;\nvector<int> petsType;\nvector<pair<int,int>> humansPos;\n\narray<array<bool, S>, S> wallCell;\n\ninline bool inb(int r, int c) {\n    return 0 <= r && r < S && 0 <= c && c < S;\n}\n\nbool is_lower_act(char c) {\n    return c == 'u' || c == 'd' || c == 'l' || c == 'r';\n}\nbool is_upper_act(char c) {\n    return c == 'U' || c == 'D' || c == 'L' || c == 'R';\n}\n\npair<int,int> apply_dir(pair<int,int> p, char ch) {\n    if (ch == 'U' || ch == 'u') return {p.first - 1, p.second};\n    if (ch == 'D' || ch == 'd') return {p.first + 1, p.second};\n    if (ch == 'L' || ch == 'l') return {p.first, p.second - 1};\n    if (ch == 'R' || ch == 'r') return {p.first, p.second + 1};\n    return p;\n}\n\nint count_dogs() {\n    int x = 0;\n    for (int t : petsType) if (t == 4) x++;\n    return x;\n}\n\nRoom make_room(int corner, int H, int W) {\n    // 0 TL, 1 TR, 2 BL, 3 BR\n    bool top = (corner == 0 || corner == 1);\n    bool left = (corner == 0 || corner == 2);\n\n    Room room;\n    if (top) {\n        room.r1 = 0;\n        room.r2 = H - 1;\n        room.br = H;\n    } else {\n        room.r1 = S - H;\n        room.r2 = S - 1;\n        room.br = S - H - 1;\n    }\n\n    if (left) {\n        room.c1 = 0;\n        room.c2 = W - 1;\n        room.bc = W;\n    } else {\n        room.c1 = S - W;\n        room.c2 = S - 1;\n        room.bc = S - W - 1;\n    }\n\n    room.centerR = (room.r1 + room.r2) / 2;\n    room.centerC = (room.c1 + room.c2) / 2;\n\n    int insideRow = top ? room.r2 : room.r1;\n    char hAct = top ? 'd' : 'u';\n\n    int d1 = room.c1 + (W - 1) / 3;\n    int d2 = room.c1 + (2 * (W - 1)) / 3;\n    if (d1 == d2) {\n        if (d2 < room.c2) d2++;\n        else if (d1 > room.c1) d1--;\n    }\n    if (d1 > d2) swap(d1, d2);\n\n    room.doors[0] = Door{room.br, d1, insideRow, d1, hAct};\n    room.doors[1] = Door{room.br, d2, insideRow, d2, hAct};\n\n    room.tasks.clear();\n\n    for (int c = room.c1; c <= room.c2; c++) {\n        if (c == d1 || c == d2) continue;\n        room.tasks.push_back(Task{room.br, c, insideRow, c, hAct});\n    }\n\n    int insideCol = left ? room.c2 : room.c1;\n    char vAct = left ? 'r' : 'l';\n    for (int r = room.r1; r <= room.r2; r++) {\n        room.tasks.push_back(Task{r, room.bc, r, insideCol, vAct});\n    }\n\n    return room;\n}\n\nint dist_to_rect(const Room& room, int r, int c) {\n    int vr = 0, vc = 0;\n    if (r < room.r1) vr = room.r1 - r;\n    else if (r > room.r2) vr = r - room.r2;\n    if (c < room.c1) vc = room.c1 - c;\n    else if (c > room.c2) vc = c - room.c2;\n    return vr + vc;\n}\n\nint nearest_door_dist(const Room& room, int r, int c) {\n    int d0 = abs(r - room.doors[0].wr) + abs(c - room.doors[0].wc);\n    int d1 = abs(r - room.doors[1].wr) + abs(c - room.doors[1].wc);\n    return min(d0, d1);\n}\n\nRoomEval evaluate_room(const Room& room) {\n    RoomEval e;\n    int reqBase = max(1, M - (count_dogs() > 0 ? 1 : 0));\n\n    e.tasks = (int)room.tasks.size();\n\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        if (room.inside(r, c)) {\n            e.insidePets++;\n            if (petsType[i] == 4) e.insideDogs++;\n        }\n        if (room.r1 - 1 <= r && r <= room.r2 + 1 &&\n            room.c1 - 1 <= c && c <= room.c2 + 1) {\n            e.expandedPets++;\n        }\n        int dd = nearest_door_dist(room, r, c);\n        if (dd <= 3) e.nearDoorPets += (4 - dd);\n        if (petsType[i] == 4 && dd <= 6) e.nearDoorDogs += (7 - dd);\n    }\n\n    vector<int> hdist;\n    hdist.reserve(M);\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = humansPos[i];\n        hdist.push_back(dist_to_rect(room, r, c));\n    }\n    sort(hdist.begin(), hdist.end());\n    for (int i = 0; i < min(reqBase, (int)hdist.size()); i++) e.sumBest += hdist[i];\n\n    // Aggressive scoring\n    {\n        double score = 0.0;\n        score += 4200.0 * room.area();\n        score -= 45.0 * e.sumBest;\n        score -= 120.0 * e.tasks;\n        score -= 330.0 * e.expandedPets;\n        score -= 850.0 * e.nearDoorPets;\n        score -= 1800.0 * e.nearDoorDogs;\n        if (e.insidePets == 0) score += 4.6e6;\n        score -= 2.5e6 * e.insidePets;\n        score -= 1.8e6 * e.insideDogs;\n        e.aggressiveScore = score;\n    }\n\n    // Safe scoring\n    {\n        double score = 0.0;\n        score += 2600.0 * room.area();\n        score -= 60.0 * e.sumBest;\n        score -= 185.0 * e.tasks;\n        score -= 650.0 * e.expandedPets;\n        score -= 1250.0 * e.nearDoorPets;\n        score -= 2900.0 * e.nearDoorDogs;\n        if (e.insidePets == 0) score += 6.2e6;\n        score -= 3.4e6 * e.insidePets;\n        score -= 2.6e6 * e.insideDogs;\n        e.safeScore = score;\n    }\n\n    return e;\n}\n\nRoom choose_room() {\n    Room bestAgg = make_room(0, 8, 8);\n    Room bestSafe = make_room(0, 6, 6);\n    RoomEval bestAggEval, bestSafeEval;\n    double bestAggScore = -1e100;\n    double bestSafeScore = -1e100;\n\n    for (int H = 5; H <= 14; H++) {\n        for (int W = 5; W <= 14; W++) {\n            for (int corner = 0; corner < 4; corner++) {\n                Room room = make_room(corner, H, W);\n                RoomEval e = evaluate_room(room);\n                if (e.aggressiveScore > bestAggScore) {\n                    bestAggScore = e.aggressiveScore;\n                    bestAgg = room;\n                    bestAggEval = e;\n                }\n            }\n        }\n    }\n\n    for (int H = 4; H <= 10; H++) {\n        for (int W = 4; W <= 10; W++) {\n            for (int corner = 0; corner < 4; corner++) {\n                Room room = make_room(corner, H, W);\n                RoomEval e = evaluate_room(room);\n                if (e.safeScore > bestSafeScore) {\n                    bestSafeScore = e.safeScore;\n                    bestSafe = room;\n                    bestSafeEval = e;\n                }\n            }\n        }\n    }\n\n    bool risky =\n        bestAggEval.insidePets > 0 ||\n        bestAggEval.insideDogs > 0 ||\n        bestAggEval.expandedPets >= 5 ||\n        bestAggEval.nearDoorDogs >= 9 ||\n        bestAggEval.sumBest >= 55 ||\n        bestAggEval.tasks >= 25;\n\n    if (risky) return bestSafe;\n    return bestAgg;\n}\n\nBFSRes bfs_from(pair<int,int> st, const array<array<bool, S>, S>& blocked) {\n    BFSRes res;\n    queue<pair<int,int>> q;\n    auto [sr, sc] = st;\n    res.dist[sr][sc] = 0;\n    res.first[sr][sc] = '.';\n    q.push(st);\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n        for (int k = 0; k < 4; k++) {\n            int nr = r + dr[k], nc = c + dc[k];\n            if (!inb(nr, nc)) continue;\n            if (blocked[nr][nc]) continue;\n            if (res.dist[nr][nc] != -1) continue;\n            res.dist[nr][nc] = res.dist[r][c] + 1;\n            res.first[nr][nc] = (res.dist[r][c] == 0 ? moveChar[k] : res.first[r][c]);\n            q.push({nr, nc});\n        }\n    }\n    return res;\n}\n\nvector<BFSRes> all_bfs(const array<array<bool, S>, S>& blocked) {\n    vector<BFSRes> v(M);\n    for (int i = 0; i < M; i++) v[i] = bfs_from(humansPos[i], blocked);\n    return v;\n}\n\nvoid rebuild_counts(array<array<int, S>, S>& humanCnt,\n                    array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            humanCnt[i][j] = 0;\n            petCnt[i][j] = 0;\n        }\n    }\n    for (auto [r, c] : humansPos) humanCnt[r][c]++;\n    for (auto [r, c] : petsPos) petCnt[r][c]++;\n}\n\nbool can_block_cell(int tr, int tc,\n                    const array<array<int, S>, S>& humanCnt,\n                    const array<array<int, S>, S>& petCnt) {\n    if (!inb(tr, tc)) return false;\n    if (humanCnt[tr][tc] > 0) return false;\n    if (petCnt[tr][tc] > 0) return false;\n    for (int k = 0; k < 4; k++) {\n        int nr = tr + dr[k], nc = tc + dc[k];\n        if (!inb(nr, nc)) continue;\n        if (petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nbool unfinished_exists(const Room& room) {\n    for (auto &t : room.tasks) {\n        if (!wallCell[t.wr][t.wc]) return true;\n    }\n    return false;\n}\n\nint pets_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : petsPos) if (room.inside(r, c)) cnt++;\n    return cnt;\n}\n\nint humans_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : humansPos) if (room.inside(r, c)) cnt++;\n    return cnt;\n}\n\nint required_inside_count(int turn) {\n    int dogCnt = count_dogs();\n    int req = M - (dogCnt > 0 ? 1 : 0);\n    if (turn >= 240) req = min(req, M - 1);\n    if (turn >= 285) req = min(req, M - 2);\n    return max(1, req);\n}\n\nbool should_close_final(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 275 && petsInside <= 1) return true;\n    if (turn >= 292 && petsInside <= 2) return true;\n    if (turn >= 298) return true;\n    return false;\n}\n\npair<int,int> decoy_target(const Room& room) {\n    int tr = (room.r1 == 0 ? 24 : 5);\n    int tc = (room.c1 == 0 ? 24 : 5);\n    return {tr, tc};\n}\n\nint live_door_risk(const Door& d) {\n    int risk = 0;\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        int dist = abs(r - d.wr) + abs(c - d.wc);\n        if (dist == 0) risk += 100000;\n        else if (dist == 1) risk += 50000;\n        else if (dist <= 3) risk += (4 - dist) * 200;\n        if (petsType[i] == 4 && dist <= 6) risk += (7 - dist) * 80;\n    }\n    return risk;\n}\n\nint assign_to_target(const Room& room,\n                     const vector<BFSRes>& bfs,\n                     vector<bool>& used,\n                     string& act,\n                     int tr, int tc,\n                     bool preferInside) {\n    int best = -1, bestD = 1e9;\n\n    bool hasInsideCandidate = false;\n    if (preferInside) {\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            if (!room.inside(humansPos[i].first, humansPos[i].second)) continue;\n            int d = bfs[i].dist[tr][tc];\n            if (d >= 0) hasInsideCandidate = true;\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (used[i]) continue;\n        if (preferInside && hasInsideCandidate &&\n            !room.inside(humansPos[i].first, humansPos[i].second)) continue;\n        int d = bfs[i].dist[tr][tc];\n        if (d < 0) continue;\n        if (d < bestD) {\n            bestD = d;\n            best = i;\n        }\n    }\n\n    if (best != -1) {\n        used[best] = true;\n        if (bestD > 0) act[best] = bfs[best].first[tr][tc];\n    }\n    return best;\n}\n\nbool try_build_door_now(const Door& door,\n                        const array<array<int, S>, S>& humanCnt,\n                        const array<array<int, S>, S>& petCnt,\n                        vector<bool>& used,\n                        string& act) {\n    if (!can_block_cell(door.wr, door.wc, humanCnt, petCnt)) return false;\n    for (int i = 0; i < M; i++) {\n        if (used[i]) continue;\n        auto [r, c] = humansPos[i];\n        if (r == door.sr && c == door.sc) {\n            act[i] = door.act;\n            used[i] = true;\n            return true;\n        }\n    }\n    return false;\n}\n\nstring plan_build_actions(const Room& room,\n                          const array<array<int, S>, S>& humanCnt,\n                          const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n\n    vector<int> unfinished;\n    for (int i = 0; i < (int)room.tasks.size(); i++) {\n        auto &t = room.tasks[i];\n        if (!wallCell[t.wr][t.wc]) unfinished.push_back(i);\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    vector<bool> humanUsed(M, false);\n    vector<bool> taskUsed(room.tasks.size(), false);\n\n    // Immediate builds\n    for (int i = 0; i < M; i++) {\n        auto [hr, hc] = humansPos[i];\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                if (can_block_cell(t.wr, t.wc, humanCnt, petCnt) && !toBlock[t.wr][t.wc]) {\n                    act[i] = t.act;\n                    humanUsed[i] = true;\n                    taskUsed[idx] = true;\n                    toBlock[t.wr][t.wc] = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    array<array<bool, S>, S> blocked = wallCell;\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) if (toBlock[i][j]) blocked[i][j] = true;\n\n    vector<BFSRes> bfs = all_bfs(blocked);\n    vector<int> assignedTask(M, -1);\n\n    while (true) {\n        int bestH = -1, bestT = -1, bestD = 1e9;\n        for (int i = 0; i < M; i++) {\n            if (humanUsed[i]) continue;\n            for (int idx : unfinished) {\n                if (taskUsed[idx]) continue;\n                auto &t = room.tasks[idx];\n                int d = bfs[i].dist[t.sr][t.sc];\n                if (d <= 0) continue;\n                if (d < bestD) {\n                    bestD = d;\n                    bestH = i;\n                    bestT = idx;\n                }\n            }\n        }\n        if (bestH == -1) break;\n        humanUsed[bestH] = true;\n        taskUsed[bestT] = true;\n        assignedTask[bestH] = bestT;\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (assignedTask[i] != -1) {\n            auto &t = room.tasks[assignedTask[i]];\n            char mv = bfs[i].first[t.sr][t.sc];\n            if (mv) act[i] = mv;\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (act[i] != '.') continue;\n        auto [hr, hc] = humansPos[i];\n\n        bool onSomeUnfinishedStance = false;\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                onSomeUnfinishedStance = true;\n                break;\n            }\n        }\n        if (onSomeUnfinishedStance) continue;\n\n        int d = bfs[i].dist[room.centerR][room.centerC];\n        if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n    }\n\n    return act;\n}\n\nstring plan_wait_actions(const Room& room, int turn,\n                         const array<array<int, S>, S>& humanCnt,\n                         const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n    vector<bool> used(M, false);\n\n    array<array<bool, S>, S> blocked = wallCell;\n    vector<BFSRes> bfs = all_bfs(blocked);\n\n    vector<int> openDoors;\n    for (int d = 0; d < 2; d++) {\n        if (!wallCell[room.doors[d].wr][room.doors[d].wc]) openDoors.push_back(d);\n    }\n\n    int insideCnt = humans_inside_count(room);\n    int needInside = required_inside_count(turn);\n    int petsInside = pets_inside_count(room);\n    bool hasDog = (count_dogs() > 0);\n    auto [decoyR, decoyC] = decoy_target(room);\n\n    if ((int)openDoors.size() == 2) {\n        int d0 = openDoors[0], d1 = openDoors[1];\n        int risk0 = live_door_risk(room.doors[d0]);\n        int risk1 = live_door_risk(room.doors[d1]);\n\n        int saferDoor = (risk0 <= risk1 ? d0 : d1);\n        int riskierDoor = (saferDoor == d0 ? d1 : d0);\n\n        bool enoughInside = (insideCnt >= needInside);\n        bool late = (turn >= 170);\n        bool emergencyRisk = (max(risk0, risk1) >= 50000); // pet adjacent/on door\n\n        bool attemptCloseOne = enoughInside || late || (emergencyRisk && turn >= 120);\n\n        if (attemptCloseOne) {\n            if (can_block_cell(room.doors[riskierDoor].wr, room.doors[riskierDoor].wc, humanCnt, petCnt)) {\n                if (!try_build_door_now(room.doors[riskierDoor], humanCnt, petCnt, used, act)) {\n                    assign_to_target(room, bfs, used, act,\n                                     room.doors[riskierDoor].sr, room.doors[riskierDoor].sc,\n                                     true);\n                }\n            } else if (late) {\n                assign_to_target(room, bfs, used, act,\n                                 room.doors[riskierDoor].sr, room.doors[riskierDoor].sc,\n                                 true);\n            }\n\n            if (enoughInside || turn >= 200) {\n                assign_to_target(room, bfs, used, act,\n                                 room.doors[saferDoor].sr, room.doors[saferDoor].sc,\n                                 true);\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            auto [r, c] = humansPos[i];\n            if (room.inside(r, c)) {\n                int d = bfs[i].dist[room.centerR][room.centerC];\n                if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n            } else {\n                if (insideCnt < needInside) {\n                    int d = bfs[i].dist[room.centerR][room.centerC];\n                    if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                } else if (hasDog && turn < 260) {\n                    int d = bfs[i].dist[decoyR][decoyC];\n                    if (d > 0) act[i] = bfs[i].first[decoyR][decoyC];\n                } else {\n                    int d = bfs[i].dist[room.centerR][room.centerC];\n                    if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                }\n            }\n        }\n        return act;\n    }\n\n    if ((int)openDoors.size() == 1) {\n        int d = openDoors[0];\n        const Door& door = room.doors[d];\n\n        bool enoughInside = (insideCnt >= needInside);\n        bool forcedLate = (turn >= 294 && insideCnt >= 1);\n        bool closeNow = (enoughInside || forcedLate) &&\n                        should_close_final(turn, petsInside) &&\n                        can_block_cell(door.wr, door.wc, humanCnt, petCnt);\n\n        if (closeNow) {\n            if (!try_build_door_now(door, humanCnt, petCnt, used, act)) {\n                assign_to_target(room, bfs, used, act, door.sr, door.sc, true);\n            }\n        } else {\n            if (enoughInside && (petsInside == 0 || turn >= 220)) {\n                assign_to_target(room, bfs, used, act, door.sr, door.sc, true);\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            auto [r, c] = humansPos[i];\n            if (room.inside(r, c)) {\n                int dd = bfs[i].dist[room.centerR][room.centerC];\n                if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n            } else {\n                if (insideCnt < needInside && turn < 285) {\n                    int dd = bfs[i].dist[room.centerR][room.centerC];\n                    if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                } else if (hasDog && turn < 260) {\n                    int dd = bfs[i].dist[decoyR][decoyC];\n                    if (dd > 0) act[i] = bfs[i].first[decoyR][decoyC];\n                } else {\n                    int dd = bfs[i].dist[room.centerR][room.centerC];\n                    if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                }\n            }\n        }\n        return act;\n    }\n\n    return act;\n}\n\nstring sanitize_actions(string act,\n                        const array<array<int, S>, S>& humanCnt,\n                        const array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_lower_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [tr, tc] = apply_dir({r, c}, a);\n        if (!can_block_cell(tr, tc, humanCnt, petCnt)) {\n            act[i] = '.';\n        }\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_lower_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [tr, tc] = apply_dir({r, c}, a);\n        if (inb(tr, tc)) toBlock[tr][tc] = true;\n    }\n\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_upper_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [nr, nc] = apply_dir({r, c}, a);\n        if (!inb(nr, nc) || wallCell[nr][nc] || toBlock[nr][nc]) {\n            act[i] = '.';\n        }\n    }\n\n    return act;\n}\n\nvoid apply_human_actions(const string& act) {\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (is_lower_act(a)) {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc)) toBlock[nr][nc] = true;\n        }\n    }\n\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) wallCell[i][j] = true;\n        }\n    }\n\n    vector<pair<int,int>> newHumans = humansPos;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (is_upper_act(a)) {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc) && !wallCell[nr][nc]) {\n                newHumans[i] = {nr, nc};\n            }\n        }\n    }\n    humansPos.swap(newHumans);\n}\n\nvoid apply_pet_moves(const vector<string>& petMoves) {\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        for (char ch : petMoves[i]) {\n            if (ch == '.') continue;\n            auto [nr, nc] = apply_dir({r, c}, ch);\n            r = nr;\n            c = nc;\n        }\n        petsPos[i] = {r, c};\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    petsPos.resize(N);\n    petsType.resize(N);\n    for (int i = 0; i < N; i++) {\n        int x, y, t;\n        cin >> x >> y >> t;\n        --x; --y;\n        petsPos[i] = {x, y};\n        petsType[i] = t;\n    }\n\n    cin >> M;\n    humansPos.resize(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        --x; --y;\n        humansPos[i] = {x, y};\n    }\n\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) wallCell[i][j] = false;\n\n    Room room = choose_room();\n\n    for (int turn = 0; turn < MAX_TURN; turn++) {\n        array<array<int, S>, S> humanCnt, petCnt;\n        rebuild_counts(humanCnt, petCnt);\n\n        string act(M, '.');\n\n        bool fullyClosed = wallCell[room.doors[0].wr][room.doors[0].wc] &&\n                           wallCell[room.doors[1].wr][room.doors[1].wc];\n\n        if (fullyClosed) {\n            act = string(M, '.');\n        } else if (unfinished_exists(room)) {\n            act = plan_build_actions(room, humanCnt, petCnt);\n        } else {\n            act = plan_wait_actions(room, turn, humanCnt, petCnt);\n        }\n\n        act = sanitize_actions(act, humanCnt, petCnt);\n\n        cout << act << '\\n' << flush;\n\n        apply_human_actions(act);\n\n        vector<string> petMoves(N);\n        for (int i = 0; i < N; i++) {\n            if (!(cin >> petMoves[i])) return 0;\n        }\n        apply_pet_moves(petMoves);\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nconstexpr int N = 20;\nconstexpr int V = N * N;\nconstexpr int LMAX = 200;\nconstexpr int NONE = 4;\nconstexpr double EPS = 1e-12;\n\nconst char ACT[4] = {'U', 'D', 'L', 'R'};\nconst int di[4] = {-1, 1, 0, 0};\nconst int dj[4] = {0, 0, -1, 1};\nconst int prefDirOrder[4] = {1, 3, 0, 2}; // D,R,U,L\nconst int isUL[4] = {1, 0, 1, 0};\n\nint si, sj, ti, tj, sid, tid;\ndouble p_forget, p_move;\n\nstring H[N];\nstring VW[N - 1];\n\nint toCell[V][4];\nunsigned char transKind[V][4]; // 0: stay, 1: move, 2: hit target\nvector<int> neighbors[V];\n\nint distToT[V];\nbool spValid[V][4];\n\ndouble hitReward[LMAX + 1];\ndouble UB[LMAX + 2][V];\n\ndouble preDist[LMAX + 1][V];\ndouble sufVal[LMAX + 2][V];\ndouble prefScore[LMAX + 1];\n\nint dpMinTurn[V][5];\nint dpMaxTurn[V][5];\n\ninline int ID(int i, int j) { return i * N + j; }\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\ninline double dot400(const double* a, const double* b) {\n    double s = 0.0;\n    for (int i = 0; i < V; i++) s += a[i] * b[i];\n    return s;\n}\n\nvoid buildTransitions() {\n    for (int c = 0; c < V; c++) neighbors[c].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = ID(i, j);\n\n            // U\n            if (i > 0 && VW[i - 1][j] == '0') toCell[c][0] = ID(i - 1, j);\n            else toCell[c][0] = c;\n\n            // D\n            if (i < N - 1 && VW[i][j] == '0') toCell[c][1] = ID(i + 1, j);\n            else toCell[c][1] = c;\n\n            // L\n            if (j > 0 && H[i][j - 1] == '0') toCell[c][2] = ID(i, j - 1);\n            else toCell[c][2] = c;\n\n            // R\n            if (j < N - 1 && H[i][j] == '0') toCell[c][3] = ID(i, j + 1);\n            else toCell[c][3] = c;\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            int nc = toCell[c][a];\n            if (nc != c) neighbors[c].push_back(nc);\n        }\n        sort(neighbors[c].begin(), neighbors[c].end());\n        neighbors[c].erase(unique(neighbors[c].begin(), neighbors[c].end()), neighbors[c].end());\n    }\n\n    // Absorbing target for safety in value DP\n    for (int a = 0; a < 4; a++) toCell[tid][a] = tid;\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c == tid) {\n                transKind[c][a] = 0;\n            } else if (toCell[c][a] == c) {\n                transKind[c][a] = 0;\n            } else if (toCell[c][a] == tid) {\n                transKind[c][a] = 2;\n            } else {\n                transKind[c][a] = 1;\n            }\n        }\n    }\n}\n\nvoid bfsDistToTarget() {\n    fill(distToT, distToT + V, -1);\n    queue<int> q;\n    distToT[tid] = 0;\n    q.push(tid);\n\n    while (!q.empty()) {\n        int c = q.front();\n        q.pop();\n        for (int nc : neighbors[c]) {\n            if (distToT[nc] == -1) {\n                distToT[nc] = distToT[c] + 1;\n                q.push(nc);\n            }\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c != tid && transKind[c][a] != 0) {\n                int nc = toCell[c][a];\n                spValid[c][a] = (distToT[nc] == distToT[c] - 1);\n            } else {\n                spValid[c][a] = false;\n            }\n        }\n    }\n}\n\nvoid computeAdaptiveUpperBound() {\n    for (int c = 0; c < V; c++) UB[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        UB[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                double val = 0.0;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val = UB[t + 1][c];\n                } else if (k == 2) {\n                    val = hitReward[t] + p_forget * UB[t + 1][c];\n                } else {\n                    int nc = toCell[c][a];\n                    val = p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc];\n                }\n                if (val > best) best = val;\n            }\n            UB[t][c] = best;\n        }\n    }\n}\n\nvector<int> greedyRollout() {\n    vector<int> seq(LMAX, 0);\n    array<double, V> dist{};\n    dist.fill(0.0);\n    dist[sid] = 1.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        int bestA = 0;\n        double bestVal = -1e100;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            double val = 0.0;\n            for (int c = 0; c < V; c++) {\n                double q = dist[c];\n                if (q < 1e-18) continue;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val += q * UB[t + 1][c];\n                } else if (k == 2) {\n                    val += q * (hitReward[t] + p_forget * UB[t + 1][c]);\n                } else {\n                    int nc = toCell[c][a];\n                    val += q * (p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc]);\n                }\n            }\n            if (val > bestVal + 1e-15) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq[t - 1] = bestA;\n\n        array<double, V> nd{};\n        nd.fill(0.0);\n        for (int c = 0; c < V; c++) {\n            double q = dist[c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][bestA];\n            if (k == 0) {\n                nd[c] += q;\n            } else if (k == 2) {\n                nd[c] += q * p_forget;\n            } else {\n                int nc = toCell[c][bestA];\n                nd[c] += q * p_forget;\n                nd[nc] += q * p_move;\n            }\n        }\n        dist = nd;\n    }\n\n    return seq;\n}\n\nstruct CurState {\n    array<double, V> dist;\n    double score;\n};\n\nstruct CandState {\n    array<double, V> dist;\n    double score;\n    double pri;\n    int parent;\n    unsigned char act;\n};\n\nstruct ParentInfo {\n    int parent;\n    unsigned char act;\n};\n\nvector<vector<int>> beamSearch(int beamWidth, int topM) {\n    vector<vector<ParentInfo>> parent(LMAX + 1);\n\n    vector<CurState> cur, nxt;\n    cur.reserve(beamWidth);\n    nxt.reserve(beamWidth);\n\n    CurState start;\n    start.dist.fill(0.0);\n    start.dist[sid] = 1.0;\n    start.score = 0.0;\n    cur.push_back(start);\n\n    vector<CandState> cand;\n    cand.reserve(beamWidth * 4);\n    vector<int> ord;\n\n    for (int t = 1; t <= LMAX; t++) {\n        cand.clear();\n\n        for (int idx = 0; idx < (int)cur.size(); idx++) {\n            const auto &st = cur[idx];\n            for (int a = 0; a < 4; a++) {\n                CandState cs;\n                cs.dist.fill(0.0);\n                cs.parent = idx;\n                cs.act = (unsigned char)a;\n                double scoreAfter = st.score;\n                double pri = st.score;\n\n                for (int c = 0; c < V; c++) {\n                    double q = st.dist[c];\n                    if (q < 1e-18) continue;\n                    unsigned char k = transKind[c][a];\n                    if (k == 0) {\n                        cs.dist[c] += q;\n                        pri += q * UB[t + 1][c];\n                    } else if (k == 2) {\n                        cs.dist[c] += q * p_forget;\n                        scoreAfter += q * hitReward[t];\n                        pri += q * (hitReward[t] + p_forget * UB[t + 1][c]);\n                    } else {\n                        int nc = toCell[c][a];\n                        cs.dist[c] += q * p_forget;\n                        cs.dist[nc] += q * p_move;\n                        pri += q * (p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc]);\n                    }\n                }\n\n                cs.score = scoreAfter;\n                cs.pri = pri;\n                cand.push_back(std::move(cs));\n            }\n        }\n\n        int k = min(beamWidth, (int)cand.size());\n        ord.resize(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n\n        auto cmp = [&](int x, int y) {\n            if (cand[x].pri != cand[y].pri) return cand[x].pri > cand[y].pri;\n            if (cand[x].score != cand[y].score) return cand[x].score > cand[y].score;\n            if (cand[x].parent != cand[y].parent) return cand[x].parent < cand[y].parent;\n            return cand[x].act < cand[y].act;\n        };\n        partial_sort(ord.begin(), ord.begin() + k, ord.end(), cmp);\n\n        nxt.clear();\n        parent[t].resize(k);\n        for (int i = 0; i < k; i++) {\n            int id = ord[i];\n            CurState ns;\n            ns.dist = cand[id].dist;\n            ns.score = cand[id].score;\n            nxt.push_back(std::move(ns));\n            parent[t][i] = ParentInfo{cand[id].parent, cand[id].act};\n        }\n        cur.swap(nxt);\n    }\n\n    vector<int> finalOrd(cur.size());\n    iota(finalOrd.begin(), finalOrd.end(), 0);\n    sort(finalOrd.begin(), finalOrd.end(), [&](int x, int y) {\n        if (cur[x].score != cur[y].score) return cur[x].score > cur[y].score;\n        return x < y;\n    });\n\n    vector<vector<int>> res;\n    topM = min(topM, (int)finalOrd.size());\n    for (int z = 0; z < topM; z++) {\n        int idx = finalOrd[z];\n        vector<int> seq(LMAX);\n        for (int t = LMAX; t >= 1; t--) {\n            seq[t - 1] = parent[t][idx].act;\n            idx = parent[t][idx].parent;\n        }\n        res.push_back(std::move(seq));\n    }\n    return res;\n}\n\nvector<int> buildShortestPathByTurns(bool maximizeTurns) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return distToT[a] < distToT[b];\n    });\n\n    const int INF = 1e9;\n\n    for (int c : ids) {\n        for (int last = 0; last < 5; last++) {\n            if (c == tid) {\n                dpMinTurn[c][last] = 0;\n                dpMaxTurn[c][last] = 0;\n                continue;\n            }\n\n            int bestMin = INF;\n            int bestMax = -INF;\n\n            for (int a = 0; a < 4; a++) {\n                if (!spValid[c][a]) continue;\n                int nc = toCell[c][a];\n                int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n                bestMin = min(bestMin, turnCost + isUL[a] + dpMinTurn[nc][a]);\n                bestMax = max(bestMax, turnCost - isUL[a] + dpMaxTurn[nc][a]);\n            }\n\n            dpMinTurn[c][last] = bestMin;\n            dpMaxTurn[c][last] = bestMax;\n        }\n    }\n\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n\n    while (c != tid) {\n        int bestA = -1;\n        int bestVal = maximizeTurns ? -INF : INF;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n            int val;\n            if (maximizeTurns) {\n                val = turnCost - isUL[a] + dpMaxTurn[nc][a];\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            } else {\n                val = turnCost + isUL[a] + dpMinTurn[nc][a];\n                if (val < bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            }\n        }\n\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n\n    return path;\n}\n\nvector<int> repeatPathTo200(const vector<int> &path) {\n    vector<int> seq(LMAX, 1);\n    if (path.empty()) return seq;\n    for (int t = 0; t < LMAX; t++) seq[t] = path[t % (int)path.size()];\n    return seq;\n}\n\nvector<int> makePeriodic(const vector<int>& pat) {\n    vector<int> seq(LMAX);\n    for (int t = 0; t < LMAX; t++) seq[t] = pat[t % (int)pat.size()];\n    return seq;\n}\n\nvector<int> randomWeightedShortestPath(XorShift64& rng, double wTurn, double wBlock, double noise) {\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n    while (c != tid) {\n        int bestA = -1;\n        double bestS = -1e100;\n        for (int a = 0; a < 4; a++) {\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            double s = 0.0;\n            if (last != NONE && last != a) s += wTurn;\n            if (nc == tid || toCell[nc][a] == nc) s += wBlock;\n            s += noise * rng.nextDouble();\n            if (s > bestS) {\n                bestS = s;\n                bestA = a;\n            }\n        }\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n    return path;\n}\n\nvoid computeForward(const vector<int> &seq) {\n    fill(preDist[0], preDist[0] + V, 0.0);\n    preDist[0][sid] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        fill(preDist[t], preDist[t] + V, 0.0);\n        int a = seq[t - 1];\n        double sc = prefScore[t - 1];\n\n        for (int c = 0; c < V; c++) {\n            double q = preDist[t - 1][c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                preDist[t][c] += q;\n            } else if (k == 2) {\n                preDist[t][c] += q * p_forget;\n                sc += q * hitReward[t];\n            } else {\n                int nc = toCell[c][a];\n                preDist[t][c] += q * p_forget;\n                preDist[t][nc] += q * p_move;\n            }\n        }\n        prefScore[t] = sc;\n    }\n}\n\ndouble exactScore(const vector<int>& seq) {\n    computeForward(seq);\n    return prefScore[LMAX];\n}\n\nvoid computeBackward(const vector<int> &seq) {\n    for (int c = 0; c < V; c++) sufVal[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        int a = seq[t - 1];\n        sufVal[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                sufVal[t][c] = sufVal[t + 1][c];\n            } else if (k == 2) {\n                sufVal[t][c] = hitReward[t] + p_forget * sufVal[t + 1][c];\n            } else {\n                int nc = toCell[c][a];\n                sufVal[t][c] = p_forget * sufVal[t + 1][c] + p_move * sufVal[t + 1][nc];\n            }\n        }\n    }\n}\n\ninline void applyActionValue(int pos, int a, const double* next, double* out) {\n    out[tid] = 0.0;\n    for (int c = 0; c < V; c++) {\n        if (c == tid) continue;\n        unsigned char k = transKind[c][a];\n        if (k == 0) {\n            out[c] = next[c];\n        } else if (k == 2) {\n            out[c] = hitReward[pos] + p_forget * next[c];\n        } else {\n            int nc = toCell[c][a];\n            out[c] = p_forget * next[c] + p_move * next[nc];\n        }\n    }\n}\n\nstruct Change {\n    int k = 0;\n    int pos = -1; // 0-based\n    int a[3] = {0, 0, 0};\n    double score = -1e100;\n};\n\nChange searchBest1(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double out[V];\n\n    for (int t = 1; t <= LMAX; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n        const double* nxt = sufVal[t + 1];\n\n        for (int a = 0; a < 4; a++) {\n            if (a == seq[t - 1]) continue;\n            applyActionValue(t, a, nxt, out);\n            double val = base + dot400(pre, out);\n            if (val > best.score + EPS) {\n                best.score = val;\n                best.k = 1;\n                best.pos = t - 1;\n                best.a[0] = a;\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest2(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double mid[4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 1; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        for (int b = 0; b < 4; b++) applyActionValue(t + 1, b, sufVal[t + 2], mid[b]);\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                if (a == seq[t - 1] && b == seq[t]) continue;\n                applyActionValue(t, a, mid[b], out);\n                double val = base + dot400(pre, out);\n                if (val > best.score + EPS) {\n                    best.score = val;\n                    best.k = 2;\n                    best.pos = t - 1;\n                    best.a[0] = a;\n                    best.a[1] = b;\n                }\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest3(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double tail[4][V];\n    static double mid[4][4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 2; t++) {\n        if ((t & 7) == 0 && Clock::now() >= deadline) break;\n\n        for (int c = 0; c < 4; c++) applyActionValue(t + 2, c, sufVal[t + 3], tail[c]);\n        for (int b = 0; b < 4; b++) {\n            for (int c = 0; c < 4; c++) {\n                applyActionValue(t + 1, b, tail[c], mid[b][c]);\n            }\n        }\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                for (int c = 0; c < 4; c++) {\n                    if (a == seq[t - 1] && b == seq[t] && c == seq[t + 1]) continue;\n                    applyActionValue(t, a, mid[b][c], out);\n                    double val = base + dot400(pre, out);\n                    if (val > best.score + EPS) {\n                        best.score = val;\n                        best.k = 3;\n                        best.pos = t - 1;\n                        best.a[0] = a;\n                        best.a[1] = b;\n                        best.a[2] = c;\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\ndouble localDescent(vector<int>& seq, const Clock::time_point& deadline, int maxIter, bool allow3) {\n    computeForward(seq);\n    double curScore = prefScore[LMAX];\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (Clock::now() >= deadline) break;\n        computeBackward(seq);\n\n        Change best = searchBest1(seq, curScore, deadline);\n        if (Clock::now() >= deadline) break;\n\n        Change c2 = searchBest2(seq, curScore, deadline);\n        if (c2.score > best.score + EPS) best = c2;\n\n        if (allow3 && best.k == 0 && iter < 8) {\n            if (Clock::now() + chrono::milliseconds(60) < deadline) {\n                Change c3 = searchBest3(seq, curScore, deadline);\n                if (c3.score > best.score + EPS) best = c3;\n            }\n        }\n\n        if (best.k == 0) break;\n\n        for (int i = 0; i < best.k; i++) seq[best.pos + i] = best.a[i];\n        computeForward(seq);\n        curScore = prefScore[LMAX];\n    }\n\n    return curScore;\n}\n\nstring seqToString(const vector<int>& seq) {\n    string s;\n    s.reserve(seq.size());\n    for (int a : seq) s.push_back(ACT[a]);\n    return s;\n}\n\nvoid perturb(vector<int>& seq, const vector<vector<int>>& pool, XorShift64& rng) {\n    int mode = rng.nextInt(4);\n\n    if (mode == 0) {\n        int len = 1 + rng.nextInt(8);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[pos + i] = rng.nextInt(4);\n    } else if (mode == 1 && !pool.empty()) {\n        int len = 5 + rng.nextInt(26);\n        len = min(len, LMAX);\n        int dst = rng.nextInt(LMAX - len + 1);\n        const auto& src = pool[rng.nextInt((int)pool.size())];\n        int srcPos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[dst + i] = src[srcPos + i];\n    } else if (mode == 2) {\n        int cnt = 2 + rng.nextInt(5);\n        for (int k = 0; k < cnt; k++) {\n            int pos = rng.nextInt(LMAX);\n            seq[pos] = rng.nextInt(4);\n        }\n    } else {\n        int len = 3 + rng.nextInt(12);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) {\n            if (rng.nextInt(3) == 0) seq[pos + i] = rng.nextInt(4);\n        }\n    }\n}\n\nuint64_t makeSeed() {\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(si); mix(sj); mix(ti); mix(tj);\n    mix((uint64_t)llround(p_forget * 1000.0));\n    for (int i = 0; i < N; i++) {\n        for (char ch : H[i]) mix((uint64_t)ch);\n    }\n    for (int i = 0; i < N - 1; i++) {\n        for (char ch : VW[i]) mix((uint64_t)ch);\n    }\n    return seed;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto globalStart = Clock::now();\n    auto deadline = globalStart + chrono::milliseconds(1950);\n\n    cin >> si >> sj >> ti >> tj >> p_forget;\n    for (int i = 0; i < N; i++) cin >> H[i];\n    for (int i = 0; i < N - 1; i++) cin >> VW[i];\n\n    sid = ID(si, sj);\n    tid = ID(ti, tj);\n    p_move = 1.0 - p_forget;\n\n    for (int t = 1; t <= LMAX; t++) hitReward[t] = p_move * (401 - t);\n\n    buildTransitions();\n    bfsDistToTarget();\n    computeAdaptiveUpperBound();\n\n    XorShift64 rng(makeSeed());\n\n    vector<vector<int>> candidates;\n    candidates.reserve(32);\n\n    // Heuristic rollout / beam\n    candidates.push_back(greedyRollout());\n    {\n        auto beams = beamSearch(90, 3);\n        for (auto& s : beams) candidates.push_back(s);\n    }\n\n    // Shortest-path extremes\n    candidates.push_back(repeatPathTo200(buildShortestPathByTurns(false)));\n    candidates.push_back(repeatPathTo200(buildShortestPathByTurns(true)));\n\n    // Randomized shortest-path variants\n    {\n        vector<tuple<double, double, double>> params = {\n            {-3.0, 0.0, 0.8},\n            { 3.0, 0.0, 0.8},\n            {-1.0, 2.0, 0.8},\n            { 1.0, 2.0, 0.8},\n            { 0.0, 3.0, 0.8},\n            {-2.0, 1.0, 1.5},\n            { 2.0, 1.0, 1.5},\n            { 0.0, 0.0, 2.0}\n        };\n        for (auto [wt, wb, nz] : params) {\n            auto pth = randomWeightedShortestPath(rng, wt, wb, nz);\n            candidates.push_back(repeatPathTo200(pth));\n        }\n    }\n\n    // Simple periodic baselines\n    candidates.push_back(makePeriodic({1, 3}));       // DRDR...\n    candidates.push_back(makePeriodic({3, 1}));       // RDRD...\n    candidates.push_back(makePeriodic({1, 1, 3, 3})); // DDRR...\n    candidates.push_back(makePeriodic({3, 3, 1, 1})); // RRDD...\n\n    // Deduplicate\n    unordered_set<string> seen;\n    vector<vector<int>> uniq;\n    uniq.reserve(candidates.size());\n    for (auto& seq : candidates) {\n        string key = seqToString(seq);\n        if (seen.insert(key).second) uniq.push_back(seq);\n    }\n\n    vector<pair<double, int>> order;\n    order.reserve(uniq.size());\n    for (int i = 0; i < (int)uniq.size(); i++) {\n        double sc = exactScore(uniq[i]);\n        order.push_back({sc, i});\n    }\n    sort(order.begin(), order.end(), greater<pair<double, int>>());\n\n    vector<int> bestSeq = uniq[order[0].second];\n    double bestScore = order[0].first;\n\n    vector<vector<int>> pool;\n    for (int z = 0; z < (int)order.size() && z < 8; z++) {\n        pool.push_back(uniq[order[z].second]);\n    }\n\n    // Improve top seeds\n    int topTrials = min(5, (int)order.size());\n    for (int z = 0; z < topTrials; z++) {\n        if (Clock::now() >= deadline) break;\n        vector<int> seq = uniq[order[z].second];\n        bool allow3 = (z == 0);\n        int maxIter = (z == 0 ? 30 : 18);\n        double sc = localDescent(seq, deadline, maxIter, allow3);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n        if ((int)pool.size() < 16) pool.push_back(seq);\n    }\n\n    // Final polish on current best\n    if (Clock::now() + chrono::milliseconds(80) < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = localDescent(seq, deadline, 20, true);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    // Perturb + re-descent\n    while (Clock::now() + chrono::milliseconds(50) < deadline) {\n        vector<int> seq = bestSeq;\n        perturb(seq, pool, rng);\n        double sc = localDescent(seq, deadline, 10, false);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n            if ((int)pool.size() < 16) pool.push_back(seq);\n        }\n    }\n\n    // One last polish\n    if (Clock::now() < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = localDescent(seq, deadline, 25, true);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    cout << seqToString(bestSeq) << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int P = N * N;\nstatic constexpr int V = P * 4;\n\nstatic constexpr int DIR_L = 0;\nstatic constexpr int DIR_U = 1;\nstatic constexpr int DIR_R = 2;\nstatic constexpr int DIR_D = 3;\n\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int MATCH_REWARD = 2;\nstatic constexpr int BROKEN_PENALTY = -3;\nstatic constexpr int BOUNDARY_PENALTY = -3;\n\nstatic constexpr long long SCORE_FACTOR = 10000000000LL;\nstatic constexpr long long L2_FACTOR = 1000000LL;\nstatic constexpr long long L1_FACTOR = 100LL;\n\nusing StateArray = array<uint8_t, P>;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 1) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0); // 53-bit\n    }\n};\n\nstruct CycleEval {\n    int L1 = 0;\n    int L2 = 0;\n    int total = 0;\n    int numCycles = 0;\n    long long score = 0;\n    long long scalarNoG = LLONG_MIN / 4;\n};\n\nstruct Eval {\n    int g = 0;\n    CycleEval c;\n    long long scalar = LLONG_MIN / 4;\n};\n\nstruct Candidate {\n    StateArray st{};\n    Eval ev;\n};\n\nstatic const int TO[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\nstatic chrono::steady_clock::time_point g_start;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ntemplate <class T>\nvoid shuffle_vec(vector<T>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.next_int(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nuint8_t activeMask[8];\nuint8_t stateToRot[8][8];\nuint8_t allowedState[P][4];\nuint8_t allowedCnt[P];\nuint8_t baseTile[P];\nbool isDoublePos[P];\nint16_t neighborPos[P][4];\n\nvector<int> allPos;\nvector<int> nonDoublePos;\nvector<int> doublePos;\nvector<array<int, 4>> blocks2x2;\nvector<array<int, 6>> windows23;\n\nint seenStamp[P];\nint curStamp = 1;\n\ninline long long make_scalar(const CycleEval& c, int g) {\n    return c.score * SCORE_FACTOR\n         + 1LL * c.L2 * L2_FACTOR\n         + 1LL * c.L1 * L1_FACTOR\n         + 2LL * c.total\n         + g;\n}\n\ninline Eval make_eval(int g, const CycleEval& c) {\n    Eval e;\n    e.g = g;\n    e.c = c;\n    e.scalar = make_scalar(c, g);\n    return e;\n}\n\ninline int rotate_state(int b, int r) {\n    if (b <= 3) return (b + r) & 3;\n    if (b <= 5) return 4 + ((b - 4 + r) & 1);\n    return 6 + ((b - 6 + r) & 1);\n}\n\nvoid init_tables() {\n    for (int s = 0; s < 8; s++) {\n        uint8_t mask = 0;\n        for (int d = 0; d < 4; d++) {\n            if (TO[s][d] != -1) mask |= uint8_t(1u << d);\n        }\n        activeMask[s] = mask;\n    }\n\n    for (int b = 0; b < 8; b++) {\n        for (int s = 0; s < 8; s++) stateToRot[b][s] = 255;\n        for (int r = 0; r < 4; r++) {\n            int s = rotate_state(b, r);\n            stateToRot[b][s] = min<int>(stateToRot[b][s], r);\n        }\n    }\n\n    allPos.reserve(P);\n    nonDoublePos.reserve(P);\n    doublePos.reserve(P);\n    blocks2x2.reserve((N - 1) * (N - 1));\n    windows23.reserve((N - 1) * (N - 2) * 2);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            neighborPos[p][DIR_L] = (j > 0 ? p - 1 : -1);\n            neighborPos[p][DIR_U] = (i > 0 ? p - N : -1);\n            neighborPos[p][DIR_R] = (j + 1 < N ? p + 1 : -1);\n            neighborPos[p][DIR_D] = (i + 1 < N ? p + N : -1);\n        }\n    }\n\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j + 1 < N; j++) {\n            blocks2x2.push_back({i * N + j, i * N + (j + 1), (i + 1) * N + j, (i + 1) * N + (j + 1)});\n        }\n    }\n\n    // 2x3 windows\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j + 2 < N; j++) {\n            windows23.push_back({\n                i * N + j, i * N + (j + 1), i * N + (j + 2),\n                (i + 1) * N + j, (i + 1) * N + (j + 1), (i + 1) * N + (j + 2)\n            });\n        }\n    }\n    // 3x2 windows\n    for (int i = 0; i + 2 < N; i++) {\n        for (int j = 0; j + 1 < N; j++) {\n            windows23.push_back({\n                i * N + j, i * N + (j + 1),\n                (i + 1) * N + j, (i + 1) * N + (j + 1),\n                (i + 2) * N + j, (i + 2) * N + (j + 1)\n            });\n        }\n    }\n}\n\ninline uint8_t get_state_override(const StateArray& st, int pos, int overridePos, uint8_t overrideState) {\n    return (pos == overridePos ? overrideState : st[pos]);\n}\n\ninline int ownerContrib(int pos, const StateArray& st, int overridePos = -1, uint8_t overrideState = 0) {\n    int i = pos / N, j = pos % N;\n    uint8_t s = get_state_override(st, pos, overridePos, overrideState);\n    uint8_t m = activeMask[s];\n    int g = 0;\n\n    if (j == 0 && (m & (1u << DIR_L))) g += BOUNDARY_PENALTY;\n    if (i == 0 && (m & (1u << DIR_U))) g += BOUNDARY_PENALTY;\n\n    if (j + 1 < N) {\n        bool a = (m >> DIR_R) & 1u;\n        bool b = (activeMask[get_state_override(st, pos + 1, overridePos, overrideState)] >> DIR_L) & 1u;\n        if (a && b) g += MATCH_REWARD;\n        else if (a != b) g += BROKEN_PENALTY;\n    } else {\n        if (m & (1u << DIR_R)) g += BOUNDARY_PENALTY;\n    }\n\n    if (i + 1 < N) {\n        bool a = (m >> DIR_D) & 1u;\n        bool b = (activeMask[get_state_override(st, pos + N, overridePos, overrideState)] >> DIR_U) & 1u;\n        if (a && b) g += MATCH_REWARD;\n        else if (a != b) g += BROKEN_PENALTY;\n    } else {\n        if (m & (1u << DIR_D)) g += BOUNDARY_PENALTY;\n    }\n\n    return g;\n}\n\ninline int localCellScore(int pos, uint8_t s, const StateArray& st) {\n    int sc = 0;\n    uint8_t mask = activeMask[s];\n    for (int d = 0; d < 4; d++) {\n        bool a = (mask >> d) & 1u;\n        int np = neighborPos[pos][d];\n        if (np == -1) {\n            if (a) sc += BOUNDARY_PENALTY;\n        } else {\n            bool b = (activeMask[st[np]] >> opp[d]) & 1u;\n            if (a && b) sc += MATCH_REWARD;\n            else if (a != b) sc += BROKEN_PENALTY;\n        }\n    }\n    return sc;\n}\n\nint calc_g(const StateArray& st) {\n    int g = 0;\n    for (int p = 0; p < P; p++) g += ownerContrib(p, st);\n    return g;\n}\n\nCycleEval evaluateCycles(const StateArray& st) {\n    CycleEval res;\n    static uint8_t vis[V];\n    static int stk[V];\n    memset(vis, 0, sizeof(vis));\n\n    int L1 = 0, L2 = 0, total = 0, numCycles = 0;\n\n    for (int p = 0; p < P; p++) {\n        uint8_t s = st[p];\n        uint8_t mask = activeMask[s];\n        int base = p << 2;\n\n        while (mask) {\n            int d = __builtin_ctz(mask);\n            mask &= mask - 1;\n            int v = base + d;\n            if (vis[v]) continue;\n\n            bool isCycle = true;\n            int vertices = 0;\n            int top = 0;\n            stk[top++] = v;\n            vis[v] = 1;\n\n            while (top) {\n                int u = stk[--top];\n                vertices++;\n\n                int pp = u >> 2;\n                int dd = u & 3;\n                uint8_t ss = st[pp];\n\n                int md = TO[ss][dd];\n                int u2 = (pp << 2) + md;\n                if (!vis[u2]) {\n                    vis[u2] = 1;\n                    stk[top++] = u2;\n                }\n\n                int np = neighborPos[pp][dd];\n                if (np != -1 && ((activeMask[st[np]] >> opp[dd]) & 1u)) {\n                    int u3 = (np << 2) + opp[dd];\n                    if (!vis[u3]) {\n                        vis[u3] = 1;\n                        stk[top++] = u3;\n                    }\n                } else {\n                    isCycle = false;\n                }\n            }\n\n            if (isCycle) {\n                int len = vertices / 2;\n                total += len;\n                numCycles++;\n                if (len > L1) {\n                    L2 = L1;\n                    L1 = len;\n                } else if (len > L2) {\n                    L2 = len;\n                }\n            }\n        }\n    }\n\n    res.L1 = L1;\n    res.L2 = L2;\n    res.total = total;\n    res.numCycles = numCycles;\n    res.score = (numCycles >= 2 ? 1LL * L1 * L2 : 0LL);\n    res.scalarNoG = res.score * SCORE_FACTOR\n                  + 1LL * res.L2 * L2_FACTOR\n                  + 1LL * res.L1 * L1_FACTOR\n                  + 2LL * res.total;\n    return res;\n}\n\nEval evaluateFull(const StateArray& st) {\n    int g = calc_g(st);\n    CycleEval c = evaluateCycles(st);\n    return make_eval(g, c);\n}\n\nvoid optimizeLocalG(StateArray& st, RNG& rng, int sweeps = 8) {\n    vector<int> order = nonDoublePos;\n    for (int sw = 0; sw < sweeps; sw++) {\n        shuffle_vec(order, rng);\n        bool changed = false;\n        for (int pos : order) {\n            uint8_t cur = st[pos];\n            int curScore = localCellScore(pos, cur, st);\n            int bestScore = curScore;\n            uint8_t bests[4];\n            int bc = 0;\n\n            for (int k = 0; k < allowedCnt[pos]; k++) {\n                uint8_t ns = allowedState[pos][k];\n                if (ns == cur) continue;\n                int sc = localCellScore(pos, ns, st);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bests[0] = ns;\n                    bc = 1;\n                } else if (sc == bestScore && sc > curScore) {\n                    bests[bc++] = ns;\n                }\n            }\n\n            if (bestScore > curScore) {\n                st[pos] = bests[rng.next_int(bc)];\n                changed = true;\n            }\n        }\n        if (!changed) break;\n    }\n}\n\nvoid optimizeG_SA(StateArray& st, RNG& rng, int steps) {\n    if (nonDoublePos.empty()) return;\n\n    int curG = calc_g(st);\n    int bestG = curG;\n    StateArray bestSt = st;\n\n    const double T0 = 4.0;\n    const double T1 = 0.03;\n\n    for (int step = 0; step < steps; step++) {\n        int pos = nonDoublePos[rng.next_int((int)nonDoublePos.size())];\n        uint8_t cur = st[pos];\n        uint8_t ns = allowedState[pos][rng.next_int(allowedCnt[pos])];\n        if (ns == cur) continue;\n\n        int before = ownerContrib(pos, st);\n        int lp = neighborPos[pos][DIR_L];\n        int up = neighborPos[pos][DIR_U];\n        if (lp != -1) before += ownerContrib(lp, st);\n        if (up != -1) before += ownerContrib(up, st);\n\n        int after = ownerContrib(pos, st, pos, ns);\n        if (lp != -1) after += ownerContrib(lp, st, pos, ns);\n        if (up != -1) after += ownerContrib(up, st, pos, ns);\n\n        int delta = after - before;\n\n        double a = (double)step / max(1, steps - 1);\n        double T = T0 * pow(T1 / T0, a);\n\n        if (delta >= 0 || rng.next_double() < exp((double)delta / T)) {\n            st[pos] = ns;\n            curG += delta;\n            if (curG > bestG) {\n                bestG = curG;\n                bestSt = st;\n            }\n        }\n    }\n\n    st = bestSt;\n}\n\nvoid addPool(vector<Candidate>& pool, const StateArray& st, int keep = 8) {\n    Candidate c;\n    c.st = st;\n    c.ev = evaluateFull(st);\n    pool.push_back(c);\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n    if ((int)pool.size() > keep) pool.resize(keep);\n}\n\nvoid applyDoublePattern(StateArray& st, int patId) {\n    for (int p : doublePos) {\n        int i = p / N, j = p % N;\n        uint8_t v = 4;\n        switch (patId) {\n            case 0: v = 4; break;\n            case 1: v = 5; break;\n            case 2: v = ((i + j) & 1) ? 4 : 5; break;\n            case 3: v = ((i + j) & 1) ? 5 : 4; break;\n            case 4: v = (i & 1) ? 4 : 5; break;\n            case 5: v = (i & 1) ? 5 : 4; break;\n            case 6: v = (j & 1) ? 4 : 5; break;\n            case 7: v = (j & 1) ? 5 : 4; break;\n            default: v = 4; break;\n        }\n        st[p] = v;\n    }\n}\n\nvoid applyDoubleRandomMode(StateArray& st, RNG& rng, int mode) {\n    if (mode == 0) {\n        for (int p : doublePos) st[p] = uint8_t(4 + rng.next_int(2));\n    } else if (mode == 1) {\n        uint8_t rowv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = rowv[p / N];\n    } else if (mode == 2) {\n        uint8_t colv[N];\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = colv[p % N];\n    } else {\n        uint8_t rowv[N], colv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(rng.next_int(2));\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(rng.next_int(2));\n        int phase = rng.next_int(2);\n        for (int p : doublePos) {\n            int i = p / N, j = p % N;\n            st[p] = uint8_t(4 + ((rowv[i] ^ colv[j] ^ phase) & 1));\n        }\n    }\n}\n\nvoid hillDoubleSingle(StateArray& st, Eval& ev, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = doublePos;\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t ns = (orig == 4 ? 5 : 4);\n            st[pos] = ns;\n\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > ev.scalar) {\n                ev.c = c2;\n                ev.scalar = sc2;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid blockDouble2x2Pass(StateArray& st, Eval& ev, RNG& rng, int passes, double deadline) {\n    vector<int> order(blocks2x2.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int bi = 0; bi < (int)order.size(); bi++) {\n            if ((bi & 31) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& b = blocks2x2[order[bi]];\n            int ps[4], k = 0;\n            for (int t = 0; t < 4; t++) if (isDoublePos[b[t]]) ps[k++] = b[t];\n            if (k <= 1) continue;\n\n            uint8_t orig[4];\n            int origMask = 0;\n            for (int t = 0; t < k; t++) {\n                orig[t] = st[ps[t]];\n                if (orig[t] == 5) origMask |= (1 << t);\n            }\n\n            int bestMask = origMask;\n            CycleEval bestC = ev.c;\n            long long bestScalar = ev.scalar;\n\n            int lim = 1 << k;\n            for (int mask = 0; mask < lim; mask++) {\n                if (mask == origMask) continue;\n                for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestScalar) {\n                    bestScalar = sc2;\n                    bestC = c2;\n                    bestMask = mask;\n                }\n            }\n\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n            if (bestMask != origMask) {\n                ev.c = bestC;\n                ev.scalar = bestScalar;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid scanDoubleWindows23Pass(StateArray& st, Eval& ev, RNG& rng, int passes, double deadline) {\n    vector<int> order(windows23.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int wi = 0; wi < (int)order.size(); wi++) {\n            if ((wi & 31) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& w = windows23[order[wi]];\n            int ps[6], k = 0;\n            for (int t = 0; t < 6; t++) if (isDoublePos[w[t]]) ps[k++] = w[t];\n            if (k < 4) continue;\n\n            int origMask = 0;\n            for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n            int bestMask = origMask;\n            CycleEval bestC = ev.c;\n            long long bestScalar = ev.scalar;\n\n            int lim = 1 << k;\n            for (int mask = 0; mask < lim; mask++) {\n                if (mask == origMask) continue;\n                for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestScalar) {\n                    bestScalar = sc2;\n                    bestC = c2;\n                    bestMask = mask;\n                }\n            }\n\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n            if (bestMask != origMask) {\n                ev.c = bestC;\n                ev.scalar = bestScalar;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid hillExactPositions(StateArray& st, Eval& ev, const vector<int>& positions, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = positions;\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t bestState = orig;\n            Eval bestEv = ev;\n\n            if (isDoublePos[pos]) {\n                uint8_t ns = (orig == 4 ? 5 : 4);\n                st[pos] = ns;\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestEv.scalar) {\n                    bestEv.c = c2;\n                    bestEv.scalar = sc2;\n                    bestState = ns;\n                }\n            } else {\n                for (int k = 0; k < allowedCnt[pos]; k++) {\n                    uint8_t ns = allowedState[pos][k];\n                    if (ns == orig) continue;\n                    st[pos] = ns;\n                    Eval e2 = evaluateFull(st);\n                    if (e2.scalar > bestEv.scalar) {\n                        bestEv = e2;\n                        bestState = ns;\n                    }\n                }\n            }\n\n            st[pos] = bestState;\n            if (bestState != orig) {\n                ev = bestEv;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid scanAll2x2Exact(StateArray& st, Eval& ev, RNG& rng, int passes, int prodLimit, double deadline) {\n    vector<int> order(blocks2x2.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int bi = 0; bi < (int)order.size(); bi++) {\n            if ((bi & 15) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& b = blocks2x2[order[bi]];\n            int pos[4] = {b[0], b[1], b[2], b[3]};\n            int cnts[4];\n            uint8_t opts[4][4];\n            int prod = 1;\n            for (int t = 0; t < 4; t++) {\n                cnts[t] = allowedCnt[pos[t]];\n                prod *= cnts[t];\n                if (prod > prodLimit) break;\n                for (int k = 0; k < cnts[t]; k++) opts[t][k] = allowedState[pos[t]][k];\n            }\n            if (prod > prodLimit || prod <= 1) continue;\n\n            uint8_t bestStates[4];\n            for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n            Eval bestEv = ev;\n\n            for (int code = 0; code < prod; code++) {\n                int x = code;\n                for (int t = 0; t < 4; t++) {\n                    st[pos[t]] = opts[t][x % cnts[t]];\n                    x /= cnts[t];\n                }\n                Eval e2 = evaluateFull(st);\n                if (e2.scalar > bestEv.scalar) {\n                    bestEv = e2;\n                    for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n                }\n            }\n\n            bool changed = false;\n            for (int t = 0; t < 4; t++) {\n                if (st[pos[t]] != bestStates[t]) changed = true;\n                st[pos[t]] = bestStates[t];\n            }\n            if (bestEv.scalar > ev.scalar) {\n                ev = bestEv;\n                improved = true;\n            } else if (!changed) {\n                // nothing\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid randomDoubleRegionSearch(StateArray& st, Eval& ev, RNG& rng, int iterations, double deadline) {\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int h = 2 + rng.next_int(2); // 2..3\n        int w = 2 + rng.next_int(2); // 2..3\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        int ps[9];\n        int k = 0;\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) ps[k++] = p;\n            }\n        }\n        if (k <= 1 || k > 8) continue;\n\n        int origMask = 0;\n        for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n        int bestMask = origMask;\n        CycleEval bestC = ev.c;\n        long long bestScalar = ev.scalar;\n\n        int lim = 1 << k;\n        for (int mask = 0; mask < lim; mask++) {\n            if (mask == origMask) continue;\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > bestScalar) {\n                bestScalar = sc2;\n                bestC = c2;\n                bestMask = mask;\n            }\n        }\n\n        for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n        if (bestMask != origMask) {\n            ev.c = bestC;\n            ev.scalar = bestScalar;\n        }\n    }\n}\n\nvector<int> buildNeighborhood(const vector<int>& touched) {\n    if (++curStamp == INT_MAX) {\n        memset(seenStamp, 0, sizeof(seenStamp));\n        curStamp = 1;\n    }\n    vector<int> res;\n    res.reserve(touched.size() * 5 + 8);\n\n    auto add = [&](int p) {\n        if (p < 0 || p >= P) return;\n        if (seenStamp[p] == curStamp) return;\n        seenStamp[p] = curStamp;\n        res.push_back(p);\n    };\n\n    for (int p : touched) {\n        add(p);\n        for (int d = 0; d < 4; d++) {\n            int np = neighborPos[p][d];\n            if (np != -1) add(np);\n        }\n    }\n    return res;\n}\n\nvoid perturb(StateArray& st, RNG& rng, int strength, vector<int>& touched) {\n    touched.clear();\n    auto touch = [&](int p) { touched.push_back(p); };\n\n    int mode = rng.next_int(100);\n\n    if (mode < 55 && !doublePos.empty()) {\n        int h = 2 + rng.next_int(3); // 2..4\n        int w = 2 + rng.next_int(3); // 2..4\n        h = min(h, N);\n        w = min(w, N);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) {\n                    if (rng.next_int(100) < 80) {\n                        st[p] = (st[p] == 4 ? 5 : 4);\n                        touch(p);\n                    }\n                } else if (rng.next_int(100) < 20) {\n                    uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n                    if (ns != st[p]) {\n                        st[p] = ns;\n                        touch(p);\n                    }\n                }\n            }\n        }\n    } else {\n        int moves = 3 + rng.next_int(4) + min(8, strength / 4);\n        for (int t = 0; t < moves; t++) {\n            int p = rng.next_int(P);\n            uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n            if (ns != st[p]) {\n                st[p] = ns;\n                touch(p);\n            }\n        }\n    }\n\n    if (touched.empty()) {\n        int p = rng.next_int(P);\n        uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n        if (ns != st[p]) st[p] = ns;\n        touch(p);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n    init_tables();\n\n    uint64_t seed = 1469598103934665603ULL;\n    vector<string> S(N);\n    for (int i = 0; i < N; i++) {\n        cin >> S[i];\n        for (char c : S[i]) {\n            seed ^= uint64_t((unsigned char)c + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    RNG rng(seed);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            int b = S[i][j] - '0';\n            baseTile[p] = (uint8_t)b;\n            isDoublePos[p] = (b == 4 || b == 5);\n            allPos.push_back(p);\n            if (isDoublePos[p]) doublePos.push_back(p);\n            else nonDoublePos.push_back(p);\n\n            int cnt = 0;\n            for (int s = 0; s < 8; s++) {\n                if (stateToRot[b][s] != 255) {\n                    allowedState[p][cnt++] = (uint8_t)s;\n                }\n            }\n            allowedCnt[p] = (uint8_t)cnt;\n        }\n    }\n\n    const double deadline = 1.95;\n\n    vector<Candidate> pool;\n    int baseStarts = 8;\n\n    for (int it = 0; it < baseStarts; it++) {\n        if (elapsed_sec() > 0.42) break;\n\n        StateArray base{};\n        for (int p = 0; p < P; p++) {\n            if (isDoublePos[p]) base[p] = 4;\n            else base[p] = allowedState[p][rng.next_int(allowedCnt[p])];\n        }\n\n        optimizeLocalG(base, rng, 6);\n        optimizeG_SA(base, rng, 22000);\n        optimizeLocalG(base, rng, 4);\n\n        for (int pat = 0; pat < 8; pat++) {\n            StateArray cand = base;\n            applyDoublePattern(cand, pat);\n            addPool(pool, cand, 8);\n        }\n        for (int mode = 0; mode < 4; mode++) {\n            StateArray cand = base;\n            applyDoubleRandomMode(cand, rng, mode);\n            addPool(pool, cand, 8);\n        }\n    }\n\n    if (pool.empty()) {\n        StateArray st{};\n        for (int p = 0; p < P; p++) st[p] = allowedState[p][0];\n        addPool(pool, st, 8);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    int refineCount = min<int>(4, pool.size());\n    for (int i = 0; i < refineCount; i++) {\n        if (elapsed_sec() > 1.10) break;\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n        blockDouble2x2Pass(pool[i].st, pool[i].ev, rng, 1, deadline);\n        if (i < 2) scanDoubleWindows23Pass(pool[i].st, pool[i].ev, rng, 1, deadline);\n        hillExactPositions(pool[i].st, pool[i].ev, allPos, rng, 1, deadline);\n        if (i == 0 && elapsed_sec() < 1.45) {\n            scanAll2x2Exact(pool[i].st, pool[i].ev, rng, 1, 64, deadline);\n        }\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    Candidate best = pool[0];\n    Candidate current = best;\n    int stagnation = 0;\n\n    while (elapsed_sec() < deadline - 0.18) {\n        StateArray trial = (rng.next_int(100) < 60 ? current.st : best.st);\n        vector<int> touched;\n        perturb(trial, rng, stagnation, touched);\n        Eval tev = evaluateFull(trial);\n\n        vector<int> neigh = buildNeighborhood(touched);\n        hillExactPositions(trial, tev, neigh, rng, 1, deadline);\n        randomDoubleRegionSearch(trial, tev, rng, 16, deadline);\n        hillDoubleSingle(trial, tev, rng, 1, deadline);\n        if (rng.next_int(100) < 35) blockDouble2x2Pass(trial, tev, rng, 1, deadline);\n\n        if (tev.scalar > best.ev.scalar) {\n            best.st = trial;\n            best.ev = tev;\n            current = best;\n            stagnation = 0;\n            pool.push_back(best);\n            sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n                return a.ev.scalar > b.ev.scalar;\n            });\n            if ((int)pool.size() > 8) pool.resize(8);\n        } else {\n            stagnation++;\n        }\n\n        if (tev.scalar > current.ev.scalar || rng.next_int(100) < (stagnation < 10 ? 18 : 30)) {\n            current.st = trial;\n            current.ev = tev;\n        }\n\n        if (stagnation >= 20 && !pool.empty()) {\n            current = pool[rng.next_int((int)pool.size())];\n            stagnation = 0;\n        }\n    }\n\n    // Final polish\n    hillDoubleSingle(best.st, best.ev, rng, 2, deadline);\n    blockDouble2x2Pass(best.st, best.ev, rng, 2, deadline);\n    if (elapsed_sec() < deadline - 0.12) scanDoubleWindows23Pass(best.st, best.ev, rng, 1, deadline);\n    if (elapsed_sec() < deadline - 0.08) scanAll2x2Exact(best.st, best.ev, rng, 1, 64, deadline);\n    hillExactPositions(best.st, best.ev, allPos, rng, 2, deadline);\n    hillDoubleSingle(best.st, best.ev, rng, 1, deadline);\n\n    string ans;\n    ans.resize(P);\n    for (int p = 0; p < P; p++) {\n        uint8_t r = stateToRot[baseTile[p]][best.st[p]];\n        if (r == 255) r = 0;\n        ans[p] = char('0' + r);\n    }\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nstatic constexpr int MAXC = 100;\nstatic constexpr uint16_t NIL = 65535;\n\nstruct FastHash {\n    static ull splitmix64(ull 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()(ull x) const {\n        static const ull FIXED_RANDOM =\n            chrono::steady_clock::now().time_since_epoch().count();\n        return (size_t)splitmix64(x + FIXED_RANDOM);\n    }\n};\n\nstruct Metrics {\n    int tree = 1;\n    int largest_comp = 1;\n    int matched = 0;\n    int components = 1;\n    int cycle_excess = 0;\n    int full_tiles = 0;\n    int sumsq = 1;\n    int pot_max = 1;\n    int pot_sum = 1;\n    int hole_bad = 0;\n    int dist = 0;\n};\n\nstruct Node {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1; // 0:U 1:D 2:L 3:R\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct Cand {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1;\n    uint16_t parent = NIL;\n    char mv = '?';\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct SearchResult {\n    string best_tree_path;\n    int best_tree = 1;\n    string best_mode_path;\n    long long best_mode_score = LLONG_MIN;\n};\n\nstruct Solver {\n    int N, T, NN, FULL;\n    array<int, MAXC> nxtU, nxtD, nxtL, nxtR;\n    array<array<int, MAXC>, 4> nxtPos{};\n    array<int, MAXC> rr{}, cc{};\n    array<array<ull, 16>, MAXC> zob{};\n    ull lastSalt[5]{};\n    int popc[16]{};\n\n    chrono::steady_clock::time_point st;\n    double total_limit_sec = 2.82;\n\n    static ull splitmix64_ref(ull &x) {\n        ull z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool time_over(double deadline) const {\n        return elapsed() >= deadline;\n    }\n\n    static int hexval(char c) {\n        if ('0' <= c && c <= '9') return c - '0';\n        return c - 'a' + 10;\n    }\n\n    static int char_to_dir(char c) {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        return 3; // R\n    }\n\n    ull state_key(ull h, int last) const {\n        return h ^ lastSalt[last + 1];\n    }\n\n    string build_path(int depth, int idx,\n                      const vector<vector<uint16_t>> &parents,\n                      const vector<vector<char>> &moves) const {\n        string res(depth, '?');\n        while (depth > 0) {\n            res[depth - 1] = moves[depth][idx];\n            idx = parents[depth][idx];\n            --depth;\n        }\n        return res;\n    }\n\n    Metrics evaluate(const array<unsigned char, MAXC> &b, int blank) const {\n        int parent[MAXC];\n        int sz[MAXC];\n        int ed[MAXC];\n        unsigned char mdeg[MAXC];\n\n        for (int i = 0; i < NN; i++) {\n            mdeg[i] = 0;\n            if (b[i] == 0) {\n                parent[i] = -1;\n                sz[i] = 0;\n                ed[i] = 0;\n            } else {\n                parent[i] = i;\n                sz[i] = 1;\n                ed[i] = 0;\n            }\n        }\n\n        auto find = [&](int x) {\n            while (parent[x] != x) {\n                parent[x] = parent[parent[x]];\n                x = parent[x];\n            }\n            return x;\n        };\n\n        auto unite_edge = [&](int a, int c) {\n            int ra = find(a), rb = find(c);\n            if (ra == rb) {\n                ed[ra]++;\n            } else {\n                if (sz[ra] < sz[rb]) swap(ra, rb);\n                parent[rb] = ra;\n                sz[ra] += sz[rb];\n                ed[ra] += ed[rb] + 1;\n            }\n        };\n\n        Metrics m;\n        m.tree = 1;\n        m.largest_comp = 1;\n        m.matched = 0;\n        m.components = 0;\n        m.cycle_excess = 0;\n        m.full_tiles = 0;\n        m.sumsq = 0;\n        m.pot_max = 1;\n        m.pot_sum = 0;\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n\n            int r = nxtR[i];\n            if (r != -1) {\n                unsigned char tr = b[r];\n                if ((t & 4) && (tr & 1)) {\n                    unite_edge(i, r);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[r]++;\n                }\n            }\n\n            int d = nxtD[i];\n            if (d != -1) {\n                unsigned char td = b[d];\n                if ((t & 8) && (td & 2)) {\n                    unite_edge(i, d);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[d]++;\n                }\n            }\n        }\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n            if ((int)mdeg[i] == popc[t]) m.full_tiles++;\n        }\n\n        for (int i = 0; i < NN; i++) {\n            if (parent[i] == i) {\n                m.components++;\n                int v = sz[i];\n                int ex = ed[i] - v + 1;\n                if (ex < 0) ex = 0;\n                m.cycle_excess += ex;\n                m.largest_comp = max(m.largest_comp, v);\n                if (ed[i] == v - 1) m.tree = max(m.tree, v);\n                m.sumsq += v * v;\n                int pot = v - 2 * ex;\n                if (pot < 0) pot = 0;\n                m.pot_max = max(m.pot_max, pot);\n                m.pot_sum += pot;\n            }\n        }\n\n        // hole conflicts: stubs pointing into the blank\n        m.hole_bad = 0;\n        int u = nxtU[blank], d = nxtD[blank], l = nxtL[blank], r = nxtR[blank];\n        if (u != -1 && (b[u] & 8)) m.hole_bad++;\n        if (d != -1 && (b[d] & 2)) m.hole_bad++;\n        if (l != -1 && (b[l] & 4)) m.hole_bad++;\n        if (r != -1 && (b[r] & 1)) m.hole_bad++;\n\n        m.dist = (N - 1 - rr[blank]) + (N - 1 - cc[blank]);\n\n        return m;\n    }\n\n    long long score_of(const Metrics &m, int mode) const {\n        if (mode == 0) {\n            // Global completion-oriented:\n            // fewer cycles/components via matched-3*cycles,\n            // more fully satisfied tiles, bigger merged regions.\n            return\n                1'000'000'000'000LL * (m.matched - 3 * m.cycle_excess) +\n                1'000'000'000LL * m.full_tiles +\n                100'000LL * m.sumsq +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        } else if (mode == 1) {\n            // Large near-tree component.\n            return\n                1'000'000'000'000LL * m.pot_max +\n                1'000'000'000LL * m.tree +\n                1'000'000LL * (m.matched - 2 * m.cycle_excess) +\n                1'000LL * m.full_tiles +\n                m.largest_comp -\n                10LL * m.hole_bad;\n        } else {\n            // Local consistency.\n            return\n                1'000'000'000'000LL * m.full_tiles +\n                1'000'000'000LL * m.matched +\n                1'000'000LL * m.pot_sum +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        }\n    }\n\n    SearchResult beam_search(const array<unsigned char, MAXC> &start_board,\n                             int start_blank,\n                             int depth_limit,\n                             int mode,\n                             int width,\n                             double deadline,\n                             int start_last = -1,\n                             ull tie_salt = 0) {\n        SearchResult res;\n\n        Node root;\n        root.b = start_board;\n        root.blank = start_blank;\n        root.last = (signed char)start_last;\n        root.h = 0;\n        for (int i = 0; i < NN; i++) root.h ^= zob[i][root.b[i]];\n\n        Metrics rm = evaluate(root.b, root.blank);\n        root.tree = (short)rm.tree;\n        root.score = score_of(rm, mode);\n\n        res.best_tree = root.tree;\n        res.best_tree_path = \"\";\n        res.best_mode_score = root.score;\n        res.best_mode_path = \"\";\n\n        if (root.tree == FULL || depth_limit == 0) return res;\n\n        vector<Node> cur, next;\n        cur.reserve(width);\n        next.reserve(width);\n        cur.push_back(root);\n\n        vector<vector<uint16_t>> parents(depth_limit + 1);\n        vector<vector<char>> moves(depth_limit + 1);\n        parents[0].push_back(NIL);\n        moves[0].push_back('?');\n\n        unordered_set<ull, FastHash> seen;\n        {\n            size_t est = (size_t)min<long long>((long long)width * min(depth_limit, 1500) + 1024LL, 2'000'000LL);\n            seen.reserve(est * 2 + 1);\n            seen.max_load_factor(0.7f);\n        }\n        seen.insert(state_key(root.h, root.last));\n\n        const int inv[4] = {1, 0, 3, 2};\n        const char dirc[4] = {'U', 'D', 'L', 'R'};\n\n        vector<Cand> cands;\n        cands.reserve(width * 3 + 8);\n\n        int blankCap = (N <= 7 ? 12 : 8);\n        int blankLastCap = 3;\n\n        for (int depth = 0; depth < depth_limit; depth++) {\n            if (time_over(deadline)) break;\n\n            cands.clear();\n\n            for (int pi = 0; pi < (int)cur.size(); pi++) {\n                if ((pi & 31) == 0 && time_over(deadline)) break;\n                const Node &nd = cur[pi];\n\n                for (int dir = 0; dir < 4; dir++) {\n                    if (nd.last != -1 && inv[dir] == nd.last) continue;\n                    int nb = nxtPos[dir][nd.blank];\n                    if (nb == -1) continue;\n\n                    unsigned char tile = nd.b[nb];\n                    ull nh = nd.h ^ zob[nd.blank][0] ^ zob[nb][tile] ^ zob[nd.blank][tile] ^ zob[nb][0];\n                    ull key = state_key(nh, dir);\n                    if (seen.find(key) != seen.end()) continue;\n\n                    Cand cd;\n                    cd.b = nd.b;\n                    cd.b[nd.blank] = tile;\n                    cd.b[nb] = 0;\n                    cd.h = nh;\n                    cd.blank = nb;\n                    cd.last = (signed char)dir;\n                    cd.parent = (uint16_t)pi;\n                    cd.mv = dirc[dir];\n\n                    Metrics m = evaluate(cd.b, cd.blank);\n                    cd.tree = (short)m.tree;\n                    cd.score = score_of(m, mode);\n\n                    cands.push_back(std::move(cd));\n\n                    if (m.tree > res.best_tree) {\n                        res.best_tree = m.tree;\n                        res.best_tree_path = build_path(depth, pi, parents, moves);\n                        res.best_tree_path.push_back(dirc[dir]);\n                        if (m.tree == FULL) return res;\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand &a, const Cand &b) {\n                if (a.score != b.score) return a.score > b.score;\n                return (a.h ^ tie_salt) < (b.h ^ tie_salt);\n            });\n\n            unordered_set<ull, FastHash> used;\n            used.reserve(cands.size() * 2 + 1);\n            used.max_load_factor(0.7f);\n\n            vector<unsigned char> blankCnt(NN, 0);\n            vector<array<unsigned char, 4>> blankLastCnt(NN);\n            for (int i = 0; i < NN; i++) blankLastCnt[i] = {0, 0, 0, 0};\n\n            next.clear();\n            parents[depth + 1].clear();\n            moves[depth + 1].clear();\n            next.reserve(width);\n            parents[depth + 1].reserve(width);\n            moves[depth + 1].reserve(width);\n\n            auto try_add = [&](const Cand &cd, bool use_cap) -> bool {\n                ull key = state_key(cd.h, cd.last);\n                if (used.find(key) != used.end()) return false;\n                if (seen.find(key) != seen.end()) return false;\n\n                if (use_cap) {\n                    if (blankCnt[cd.blank] >= blankCap) return false;\n                    if (blankLastCnt[cd.blank][cd.last] >= blankLastCap) return false;\n                }\n\n                used.insert(key);\n                seen.insert(key);\n                blankCnt[cd.blank]++;\n                blankLastCnt[cd.blank][cd.last]++;\n\n                Node nd;\n                nd.b = cd.b;\n                nd.h = cd.h;\n                nd.blank = cd.blank;\n                nd.last = cd.last;\n                nd.tree = cd.tree;\n                nd.score = cd.score;\n                next.push_back(std::move(nd));\n                parents[depth + 1].push_back(cd.parent);\n                moves[depth + 1].push_back(cd.mv);\n\n                if (cd.score > res.best_mode_score) {\n                    res.best_mode_score = cd.score;\n                    res.best_mode_path = build_path(depth + 1, (int)next.size() - 1, parents, moves);\n                }\n                return true;\n            };\n\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, true);\n            }\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, false);\n            }\n\n            if (next.empty()) break;\n            cur.swap(next);\n        }\n\n        return res;\n    }\n\n    void apply_moves(array<unsigned char, MAXC> &b, int &blank, const string &path) const {\n        for (char c : path) {\n            int dir = char_to_dir(c);\n            int nb = nxtPos[dir][blank];\n            unsigned char tile = b[nb];\n            b[blank] = tile;\n            b[nb] = 0;\n            blank = nb;\n        }\n    }\n\n    bool better_solution(int treeA, int lenA, int treeB, int lenB) const {\n        if (treeA != treeB) return treeA > treeB;\n        if (treeA == FULL && treeB == FULL) return lenA < lenB;\n        return false;\n    }\n\n    int base_width() const {\n        if (N <= 6) return 2200;\n        if (N == 7) return 1600;\n        if (N == 8) return 950;\n        if (N == 9) return 650;\n        return 450;\n    }\n\n    void solve() {\n        cin >> N >> T;\n        NN = N * N;\n        FULL = NN - 1;\n\n        array<unsigned char, MAXC> init_board{};\n        int init_blank = -1;\n        for (int i = 0; i < N; i++) {\n            string s;\n            cin >> s;\n            for (int j = 0; j < N; j++) {\n                int v = hexval(s[j]);\n                init_board[i * N + j] = (unsigned char)v;\n                if (v == 0) init_blank = i * N + j;\n            }\n        }\n\n        for (int i = 0; i < 16; i++) popc[i] = __builtin_popcount(i);\n\n        for (int i = 0; i < NN; i++) {\n            int r = i / N, c = i % N;\n            rr[i] = r;\n            cc[i] = c;\n            nxtU[i] = (r > 0 ? i - N : -1);\n            nxtD[i] = (r + 1 < N ? i + N : -1);\n            nxtL[i] = (c > 0 ? i - 1 : -1);\n            nxtR[i] = (c + 1 < N ? i + 1 : -1);\n            nxtPos[0][i] = nxtU[i];\n            nxtPos[1][i] = nxtD[i];\n            nxtPos[2][i] = nxtL[i];\n            nxtPos[3][i] = nxtR[i];\n        }\n\n        ull seed = 0x123456789abcdef0ULL;\n        for (int i = 0; i < NN; i++) {\n            for (int v = 0; v < 16; v++) zob[i][v] = splitmix64_ref(seed);\n        }\n        for (int i = 0; i < 5; i++) lastSalt[i] = splitmix64_ref(seed);\n\n        st = chrono::steady_clock::now();\n\n        Metrics initM = evaluate(init_board, init_blank);\n        string best_path = \"\";\n        int best_tree = initM.tree;\n\n        int W = base_width();\n\n        double d1 = total_limit_sec * 0.40;\n        double d2 = total_limit_sec * 0.72;\n        double d3 = total_limit_sec * 0.90;\n        double d4 = total_limit_sec - 0.02;\n\n        ull salt1 = splitmix64_ref(seed);\n        ull salt2 = splitmix64_ref(seed);\n        ull salt3 = splitmix64_ref(seed);\n        ull salt4 = splitmix64_ref(seed);\n\n        SearchResult r0, r1;\n\n        // Run 1: global-completion beam\n        if (!time_over(d1)) {\n            r0 = beam_search(init_board, init_blank, T, 0, W, d1, -1, salt1);\n            if (better_solution(r0.best_tree, (int)r0.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r0.best_tree;\n                best_path = r0.best_tree_path;\n            }\n        }\n\n        // Run 2: big-near-tree beam\n        if (!time_over(d2)) {\n            r1 = beam_search(init_board, init_blank, T, 1, (W * 3) / 4, d2, -1, salt2);\n            if (better_solution(r1.best_tree, (int)r1.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r1.best_tree;\n                best_path = r1.best_tree_path;\n            }\n        }\n\n        // Choose a promising intermediate path for refinement.\n        vector<string> candidates;\n        candidates.push_back(best_path);\n        candidates.push_back(r0.best_mode_path);\n        candidates.push_back(r1.best_mode_path);\n        candidates.push_back(r0.best_tree_path);\n        candidates.push_back(r1.best_tree_path);\n\n        sort(candidates.begin(), candidates.end());\n        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());\n\n        string refine_start = best_path;\n        long long refine_best_score = LLONG_MIN;\n        int refine_best_len = (int)best_path.size();\n\n        for (const string &p : candidates) {\n            if ((int)p.size() > T) continue;\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, p);\n            Metrics m = evaluate(b, blank);\n            long long sc = score_of(m, 0); // completion-oriented\n            if (sc > refine_best_score || (sc == refine_best_score && (int)p.size() < refine_best_len)) {\n                refine_best_score = sc;\n                refine_best_len = (int)p.size();\n                refine_start = p;\n            }\n        }\n\n        // Refinement 1 from the most completion-promising state.\n        if (!time_over(d3) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, refine_start);\n            int rem = T - (int)refine_start.size();\n            int stlast = refine_start.empty() ? -1 : char_to_dir(refine_start.back());\n            if (rem > 0) {\n                auto rr0 = beam_search(b, blank, rem, 0, (W * 2) / 3, d3, stlast, salt3);\n                string cand_path = refine_start + rr0.best_tree_path;\n                if (better_solution(rr0.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr0.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        // Refinement 2 from current best tree state, slightly different heuristic.\n        if (!time_over(d4) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, best_path);\n            int rem = T - (int)best_path.size();\n            int stlast = best_path.empty() ? -1 : char_to_dir(best_path.back());\n            if (rem > 0) {\n                auto rr1 = beam_search(b, blank, rem, 1, max(120, W / 2), d4, stlast, salt4);\n                string cand_path = best_path + rr1.best_tree_path;\n                if (better_solution(rr1.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr1.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        cout << best_path << '\\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}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int R = 10000;\nstatic constexpr int MAX_CUTS = 100;\nstatic constexpr int NORMAL_MAX = 4096;\nstatic constexpr int MIN_NORM = 1000;\nstatic constexpr long double SQRT3 = 1.7320508075688772935L;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Line {\n    int A, B; // primitive, sign-normalized\n    ll C;     // A x + B y = C\n};\n\nstruct State {\n    vector<int> cell;      // cell id for each point\n    vector<int> cellSize;  // strawberries per cell\n    array<int, 11> hist{}; // hist[d] = #cells with d strawberries\n    int rawScore = 0;      // sum min(a_d, hist[d])\n    int smallCount = 0;    // #cells with size 1..10\n    int mass10 = 0;        // sum min(cell_size, 10)\n};\n\nstruct Cand2 {\n    int A, B;\n    int t1, t2;\n    double alpha1, alpha2;\n    double off1, off2;\n};\n\nstruct Cand3 {\n    array<pair<int,int>,3> n;\n    int t[3];\n    double alpha[3];\n    double off[3];\n};\n\nstruct BestLineRes {\n    bool ok = false;\n    int raw = -1000000000;\n    int mass10 = -1000000000;\n    int small = -1000000000;\n    Line line{};\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed ? seed : 88172645463393265ull) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double uniform() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    double uniform(double l, double r) {\n        return l + (r - l) * uniform();\n    }\n    ll next_ll(ll l, ll r) {\n        if (l > r) swap(l, r);\n        unsigned long long w = (unsigned long long)(r - l + 1);\n        return l + (ll)(next() % w);\n    }\n    int next_int(int l, int r) {\n        return (int)next_ll(l, r);\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\nint N, K;\nint a_need[11];\nint attendees_sum = 0;\nvector<Pt> pts;\nXorShift64 rng;\n\ntemplate <class T>\nT clampv(T x, T l, T r) {\n    return min(r, max(l, x));\n}\n\nstatic inline ll proj(int A, int B, const Pt& p) {\n    return 1LL * A * p.x + 1LL * B * p.y;\n}\n\nstatic inline ll norm2(pair<int,int> p) {\n    return 1LL * p.first * p.first + 1LL * p.second * p.second;\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\npair<int,int> normalize_pair(ll A, ll B) {\n    if (A == 0 && B == 0) return {0, 0};\n    ll g = std::gcd(std::llabs(A), std::llabs(B));\n    A /= g;\n    B /= g;\n    if (A < 0 || (A == 0 && B < 0)) {\n        A = -A;\n        B = -B;\n    }\n    return {(int)A, (int)B};\n}\n\npair<int,int> random_primitive_large() {\n    while (true) {\n        ll A = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        ll B = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        if (A == 0 && B == 0) continue;\n        auto p = normalize_pair(A, B);\n        if (norm2(p) < 1LL * MIN_NORM * MIN_NORM) continue;\n        return p;\n    }\n}\n\npair<int,int> rotate60(pair<int,int> p) {\n    long double x = 0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first + 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\npair<int,int> rotate120(pair<int,int> p) {\n    long double x = -0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first - 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\nbool better_metrics(int raw1, int mass1, int small1,\n                    int raw2, int mass2, int small2) {\n    if (raw1 != raw2) return raw1 > raw2;\n    if (mass1 != mass2) return mass1 > mass2;\n    return small1 > small2;\n}\n\nbool same_metrics(int raw1, int mass1, int small1,\n                  int raw2, int mass2, int small2) {\n    return raw1 == raw2 && mass1 == mass2 && small1 == small2;\n}\n\nint compute_raw_from_hist(const array<int,11>& hist) {\n    int raw = 0;\n    for (int d = 1; d <= 10; d++) raw += min(a_need[d], hist[d]);\n    return raw;\n}\n\nvoid recompute_score(State& st) {\n    st.hist.fill(0);\n    st.smallCount = 0;\n    st.mass10 = 0;\n    for (int s : st.cellSize) {\n        if (1 <= s && s <= 10) {\n            st.hist[s]++;\n            st.smallCount++;\n        }\n        st.mass10 += min(s, 10);\n    }\n    st.rawScore = compute_raw_from_hist(st.hist);\n}\n\nint index_from_proj(ll u, ll start, ll step, int t) {\n    ll d = u - start;\n    if (d < 0) return 0;\n    ll q = d / step;\n    if (q >= t) return t;\n    if (d % step == 0) return -1; // on a cut line\n    return (int)q + 1;\n}\n\nint raw_from_counts(const vector<int>& cnt) {\n    array<int,11> hist{};\n    for (int c : cnt) if (1 <= c && c <= 10) hist[c]++;\n    return compute_raw_from_hist(hist);\n}\n\nint eval_cand2(const Cand2& c) {\n    static vector<int> cnt;\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    int A1 = c.A, B1 = c.B;\n    auto n2 = normalize_pair(-c.B, c.A);\n    int A2 = n2.first, B2 = n2.second;\n\n    int W = c.t2 + 1;\n    int SZ = (c.t1 + 1) * (c.t2 + 1);\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int i = index_from_proj(proj(A1, B1, p), start1, step1, c.t1);\n        if (i < 0) continue;\n        int j = index_from_proj(proj(A2, B2, p), start2, step2, c.t2);\n        if (j < 0) continue;\n        cnt[i * W + j]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nint eval_cand3(const Cand3& c) {\n    static vector<int> cnt;\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    int W1 = c.t[1] + 1;\n    int W2 = c.t[2] + 1;\n    int SZ = (c.t[0] + 1) * W1 * W2;\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int idx[3];\n        bool bad = false;\n        for (int k = 0; k < 3; k++) {\n            idx[k] = index_from_proj(proj(c.n[k].first, c.n[k].second, p), start[k], step[k], c.t[k]);\n            if (idx[k] < 0) {\n                bad = true;\n                break;\n            }\n        }\n        if (bad) continue;\n        int id = (idx[0] * W1 + idx[1]) * W2 + idx[2];\n        cnt[id]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nbool has_collision_line(int A, int B, ll C) {\n    for (const auto& p : pts) {\n        if (proj(A, B, p) == C) return true;\n    }\n    return false;\n}\n\nll find_valid_C_near(int A, int B, ll base, unordered_set<ll>& used) {\n    auto bad = [&](ll C)->bool {\n        if (used.find(C) != used.end()) return true;\n        return has_collision_line(A, B, C);\n    };\n    if (!bad(base)) return base;\n    for (ll d = 1;; d++) {\n        if (!bad(base + d)) return base + d;\n        if (!bad(base - d)) return base - d;\n    }\n}\n\nvector<Line> build_lines2(const Cand2& c) {\n    auto n1 = normalize_pair(c.A, c.B);\n    auto n2 = normalize_pair(-c.B, c.A);\n\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    vector<Line> res;\n    res.reserve(c.t1 + c.t2);\n\n    unordered_set<ll> used1, used2;\n    used1.reserve(c.t1 * 2 + 3);\n    used2.reserve(c.t2 * 2 + 3);\n\n    for (int j = 0; j < c.t1; j++) {\n        ll C = start1 + 1LL * j * step1;\n        C = find_valid_C_near(n1.first, n1.second, C, used1);\n        used1.insert(C);\n        res.push_back(Line{n1.first, n1.second, C});\n    }\n    for (int j = 0; j < c.t2; j++) {\n        ll C = start2 + 1LL * j * step2;\n        C = find_valid_C_near(n2.first, n2.second, C, used2);\n        used2.insert(C);\n        res.push_back(Line{n2.first, n2.second, C});\n    }\n    return res;\n}\n\nvector<Line> build_lines3(const Cand3& c) {\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    vector<Line> res;\n    res.reserve(c.t[0] + c.t[1] + c.t[2]);\n\n    unordered_set<ll> used[3];\n    for (int k = 0; k < 3; k++) used[k].reserve(c.t[k] * 2 + 3);\n\n    for (int k = 0; k < 3; k++) {\n        auto n = normalize_pair(c.n[k].first, c.n[k].second);\n        for (int j = 0; j < c.t[k]; j++) {\n            ll C = start[k] + 1LL * j * step[k];\n            C = find_valid_C_near(n.first, n.second, C, used[k]);\n            used[k].insert(C);\n            res.push_back(Line{n.first, n.second, C});\n        }\n    }\n    return res;\n}\n\nvoid apply_line(State& st, const Line& ln) {\n    int M = (int)st.cellSize.size();\n\n    static vector<int> pos, neg, newPosId, newNegId;\n    static vector<unsigned char> side;\n\n    pos.assign(M, 0);\n    neg.assign(M, 0);\n    side.assign(N, 0);\n\n    for (int i = 0; i < N; i++) {\n        ll v = proj(ln.A, ln.B, pts[i]) - ln.C;\n        int id = st.cell[i];\n        if (v > 0) {\n            side[i] = 1;\n            pos[id]++;\n        } else {\n            side[i] = 0;\n            neg[id]++;\n        }\n    }\n\n    newPosId.assign(M, -1);\n    newNegId.assign(M, -1);\n    vector<int> newSizes;\n    newSizes.reserve(min(N, 2 * M));\n\n    for (int id = 0; id < M; id++) {\n        if (neg[id] > 0) {\n            newNegId[id] = (int)newSizes.size();\n            newSizes.push_back(neg[id]);\n        }\n        if (pos[id] > 0) {\n            newPosId[id] = (int)newSizes.size();\n            newSizes.push_back(pos[id]);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        int old = st.cell[i];\n        st.cell[i] = side[i] ? newPosId[old] : newNegId[old];\n    }\n    st.cellSize.swap(newSizes);\n    recompute_score(st);\n}\n\nState build_state_excluding(const vector<Line>& lines, int skip = -1) {\n    State st;\n    st.cell.assign(N, 0);\n    st.cellSize = {N};\n    recompute_score(st);\n    for (int i = 0; i < (int)lines.size(); i++) {\n        if (i == skip) continue;\n        apply_line(st, lines[i]);\n    }\n    return st;\n}\n\nState build_state(const vector<Line>& lines) {\n    return build_state_excluding(lines, -1);\n}\n\ndouble estimate_lambda_star() {\n    double bestLam = max(1.0, (double)N / attendees_sum);\n    double bestVal = -1e100;\n    for (double lam = 0.8; lam <= 10.0; lam += 0.02) {\n        double C = N / lam;\n        double p = exp(-lam);\n        double cur = 0.0;\n        double pk = p;\n        for (int d = 1; d <= 10; d++) {\n            pk *= lam / d;\n            cur += min<double>(a_need[d], C * pk);\n        }\n        if (cur > bestVal) {\n            bestVal = cur;\n            bestLam = lam;\n        }\n    }\n    return bestLam;\n}\n\nCand2 random_cand2(double lambdaCenter) {\n    Cand2 c;\n    auto n = random_primitive_large();\n    c.A = n.first;\n    c.B = n.second;\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.85, 0.85)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double aspect = exp(rng.uniform(-0.8, 0.8));\n    double prod = 4.0 * Ctarget / acos(-1.0);\n\n    c.t1 = max(1, (int)llround(sqrt(prod * aspect) - 1.0));\n    c.t2 = max(1, (int)llround(sqrt(prod / aspect) - 1.0));\n\n    int sum = c.t1 + c.t2;\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        c.t1 = max(1, (int)floor(c.t1 * sc));\n        c.t2 = max(1, (int)floor(c.t2 * sc));\n        while (c.t1 + c.t2 > MAX_CUTS) {\n            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n            else if (c.t2 > 1) c.t2--;\n            else break;\n        }\n    }\n\n    c.alpha1 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.alpha2 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.off1 = rng.uniform(-0.5, 0.5);\n    c.off2 = rng.uniform(-0.5, 0.5);\n    return c;\n}\n\nCand3 random_cand3(double lambdaCenter) {\n    Cand3 c;\n    while (true) {\n        auto n0 = random_primitive_large();\n        auto n1 = rotate60(n0);\n        auto n2 = rotate120(n0);\n        if ((n1.first || n1.second) && (n2.first || n2.second)\n            && norm2(n1) >= 250000 && norm2(n2) >= 250000) {\n            c.n[0] = n0;\n            c.n[1] = n1;\n            c.n[2] = n2;\n            break;\n        }\n    }\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.8, 0.8)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double base = sqrt(max(1.0, Ctarget / 3.0));\n\n    for (int k = 0; k < 3; k++) {\n        c.t[k] = max(1, (int)llround(base * exp(rng.uniform(-0.45, 0.45))));\n    }\n\n    int sum = c.t[0] + c.t[1] + c.t[2];\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        for (int k = 0; k < 3; k++) c.t[k] = max(1, (int)floor(c.t[k] * sc));\n        while (c.t[0] + c.t[1] + c.t[2] > MAX_CUTS) {\n            int id = 0;\n            if (c.t[1] > c.t[id]) id = 1;\n            if (c.t[2] > c.t[id]) id = 2;\n            if (c.t[id] > 1) c.t[id]--;\n            else break;\n        }\n    }\n\n    for (int k = 0; k < 3; k++) {\n        c.alpha[k] = clampv(exp(rng.uniform(-0.35, 0.35)), 0.55, 1.6);\n        c.off[k] = rng.uniform(-0.5, 0.5);\n    }\n    return c;\n}\n\nvector<pair<int,int>> unique_normals(const vector<Line>& lines) {\n    set<pair<int,int>> s;\n    for (const auto& ln : lines) s.insert(normalize_pair(ln.A, ln.B));\n    return vector<pair<int,int>>(s.begin(), s.end());\n}\n\npair<int,int> combine_normals(pair<int,int> a, pair<int,int> b, int sign) {\n    ll A = (ll)a.first + sign * (ll)b.first;\n    ll B = (ll)a.second + sign * (ll)b.second;\n    auto p = normalize_pair(A, B);\n    if (p.first == 0 && p.second == 0) return random_primitive_large();\n    return p;\n}\n\nuint64_t norm_key(pair<int,int> p) {\n    uint64_t a = (uint32_t)(p.first + 1000000000);\n    uint64_t b = (uint32_t)(p.second + 1000000000);\n    return (a << 32) ^ b;\n}\n\nvoid add_normal(vector<pair<int,int>>& out, unordered_set<uint64_t>& seen, pair<int,int> n) {\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return;\n    uint64_t key = norm_key(n);\n    if (seen.insert(key).second) out.push_back(n);\n}\n\nvoid dedup_normals(vector<pair<int,int>>& v) {\n    vector<pair<int,int>> out;\n    unordered_set<uint64_t> seen;\n    seen.reserve(v.size() * 2 + 3);\n    for (auto n : v) add_normal(out, seen, n);\n    v.swap(out);\n}\n\nint pick_biased_point(const State& st) {\n    int best = rng.next_int(0, N - 1);\n    for (int t = 0; t < 2; t++) {\n        int x = rng.next_int(0, N - 1);\n        if (st.cellSize[st.cell[x]] > st.cellSize[st.cell[best]]) best = x;\n    }\n    return best;\n}\n\nvector<pair<int,int>> make_candidate_normals(const State& st, const vector<Line>& lines, int want) {\n    vector<pair<int,int>> out;\n    unordered_set<uint64_t> seen;\n    seen.reserve(want * 4 + 32);\n\n    vector<pair<int,int>> fixed = {\n        {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {3,1}, {1,3}, {2,3}, {3,2}\n    };\n    for (auto n : fixed) add_normal(out, seen, n);\n\n    auto base = unique_normals(lines);\n    shuffle(base.begin(), base.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int i = 0; i < (int)base.size() && (int)out.size() < want; i++) {\n        add_normal(out, seen, base[i]);\n        if ((int)out.size() >= want) break;\n        add_normal(out, seen, normalize_pair(-base[i].second, base[i].first));\n    }\n\n    int m = min(6, (int)base.size());\n    for (int i = 0; i < m && (int)out.size() < want; i++) {\n        for (int j = i + 1; j < m && (int)out.size() < want; j++) {\n            add_normal(out, seen, combine_normals(base[i], base[j], +1));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, combine_normals(base[i], base[j], -1));\n        }\n    }\n\n    // centroid directions of largest cells\n    {\n        int M = (int)st.cellSize.size();\n        vector<pair<int,int>> top;\n        top.reserve(M);\n        for (int id = 0; id < M; id++) top.push_back({st.cellSize[id], id});\n        sort(top.begin(), top.end(), [&](auto& l, auto& r){ return l.first > r.first; });\n\n        int take = min(4, (int)top.size());\n        vector<int> ids(take);\n        for (int i = 0; i < take; i++) ids[i] = top[i].second;\n\n        vector<ll> sx(take, 0), sy(take, 0);\n        for (int i = 0; i < N; i++) {\n            int c = st.cell[i];\n            for (int j = 0; j < take; j++) {\n                if (ids[j] == c) {\n                    sx[j] += pts[i].x;\n                    sy[j] += pts[i].y;\n                    break;\n                }\n            }\n        }\n\n        for (int i = 0; i < take && (int)out.size() < want; i++) {\n            for (int j = i + 1; j < take && (int)out.size() < want; j++) {\n                ll dx = sx[j] * st.cellSize[ids[i]] - sx[i] * st.cellSize[ids[j]];\n                ll dy = sy[j] * st.cellSize[ids[i]] - sy[i] * st.cellSize[ids[j]];\n                add_normal(out, seen, normalize_pair(dx, dy));\n                if ((int)out.size() >= want) break;\n                add_normal(out, seen, normalize_pair(-dy, dx));\n            }\n        }\n    }\n\n    // pairs from same large cell\n    for (int t = 0; t < 6 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int ci = st.cell[i];\n        int j = -1;\n        for (int rep = 0; rep < 14; rep++) {\n            int x = rng.next_int(0, N - 1);\n            if (x != i && st.cell[x] == ci) {\n                j = x;\n                break;\n            }\n        }\n        if (j != -1) {\n            int dx = pts[j].x - pts[i].x;\n            int dy = pts[j].y - pts[i].y;\n            add_normal(out, seen, normalize_pair(dx, dy));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, normalize_pair(-dy, dx));\n        }\n    }\n\n    // arbitrary biased pairs\n    for (int t = 0; t < 8 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int j = pick_biased_point(st);\n        if (i == j) continue;\n        int dx = pts[j].x - pts[i].x;\n        int dy = pts[j].y - pts[i].y;\n        add_normal(out, seen, normalize_pair(dx, dy));\n        if ((int)out.size() >= want) break;\n        add_normal(out, seen, normalize_pair(-dy, dx));\n    }\n\n    while ((int)out.size() < want) add_normal(out, seen, random_primitive_large());\n    return out;\n}\n\nBestLineRes best_line_for_normal(const State& st, pair<int,int> n) {\n    BestLineRes res;\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return res;\n\n    static vector<pair<ll,int>> ord;\n    static vector<int> negCnt, tmpCnt, touched;\n\n    ord.resize(N);\n    for (int i = 0; i < N; i++) ord[i] = {proj(n.first, n.second, pts[i]), i};\n    sort(ord.begin(), ord.end());\n\n    int M = (int)st.cellSize.size();\n    negCnt.assign(M, 0);\n    tmpCnt.assign(M, 0);\n    touched.clear();\n\n    auto hist = st.hist;\n    int small = st.smallCount;\n    int mass10 = st.mass10;\n\n    int bestRaw = st.rawScore;\n    int bestMass = st.mass10;\n    int bestSmall = st.smallCount;\n    ll bestC = 0;\n    bool found = false;\n\n    int i = 0;\n    while (i < N) {\n        ll u = ord[i].first;\n        touched.clear();\n        int j = i;\n        while (j < N && ord[j].first == u) {\n            int id = st.cell[ord[j].second];\n            if (tmpCnt[id] == 0) touched.push_back(id);\n            tmpCnt[id]++;\n            j++;\n        }\n\n        for (int id : touched) {\n            int r = tmpCnt[id];\n            tmpCnt[id] = 0;\n\n            int s = st.cellSize[id];\n            int k = negCnt[id];\n            int p = s - k;\n\n            if (1 <= k && k <= 10) hist[k]--;\n            if (1 <= p && p <= 10) hist[p]--;\n\n            small -= (1 <= k && k <= 10);\n            small -= (1 <= p && p <= 10);\n            mass10 -= min(k, 10);\n            mass10 -= min(p, 10);\n\n            int k2 = k + r;\n            int p2 = s - k2;\n            negCnt[id] = k2;\n\n            if (1 <= k2 && k2 <= 10) hist[k2]++;\n            if (1 <= p2 && p2 <= 10) hist[p2]++;\n\n            small += (1 <= k2 && k2 <= 10);\n            small += (1 <= p2 && p2 <= 10);\n            mass10 += min(k2, 10);\n            mass10 += min(p2, 10);\n        }\n\n        if (j < N && ord[j].first > u + 1) {\n            int raw = compute_raw_from_hist(hist);\n            if (better_metrics(raw, mass10, small, bestRaw, bestMass, bestSmall)) {\n                bestRaw = raw;\n                bestMass = mass10;\n                bestSmall = small;\n                bestC = u + 1;\n                found = true;\n            }\n        }\n        i = j;\n    }\n\n    if (!found) return res;\n    res.ok = true;\n    res.raw = bestRaw;\n    res.mass10 = bestMass;\n    res.small = bestSmall;\n    res.line = Line{n.first, n.second, bestC};\n    return res;\n}\n\nbool better_init_sol(const State& s1, int l1, const State& s2, int l2) {\n    if (s1.rawScore != s2.rawScore) return s1.rawScore > s2.rawScore;\n    if (s1.mass10 != s2.mass10) return s1.mass10 > s2.mass10;\n    if (s1.smallCount != s2.smallCount) return s1.smallCount > s2.smallCount;\n    return l1 < l2;\n}\n\nbool try_add_one_exact(State& cur, vector<Line>& curLines, int wantNormals, bool allowSetup) {\n    if ((int)curLines.size() >= K) return false;\n\n    auto cands = make_candidate_normals(cur, curLines, wantNormals);\n\n    BestLineRes best;\n    best.raw = cur.rawScore;\n    best.mass10 = cur.mass10;\n    best.small = cur.smallCount;\n\n    for (auto n : cands) {\n        auto r = best_line_for_normal(cur, n);\n        if (!r.ok) continue;\n        if (better_metrics(r.raw, r.mass10, r.small, best.raw, best.mass10, best.small)) {\n            best = r;\n        }\n    }\n\n    if (best.ok && best.raw > cur.rawScore) {\n        apply_line(cur, best.line);\n        curLines.push_back(best.line);\n        return true;\n    }\n\n    // very conservative setup move\n    if (allowSetup && best.ok &&\n        best.raw == cur.rawScore &&\n        best.mass10 >= cur.mass10 + 9 &&\n        (int)curLines.size() + 8 < K) {\n        apply_line(cur, best.line);\n        curLines.push_back(best.line);\n        return true;\n    }\n\n    return false;\n}\n\nbool prune_once(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n    vector<int> order(curLines.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int idp = 0; idp < (int)order.size(); idp++) {\n        if (timer.elapsed() >= endTime) break;\n        int idx = order[idp];\n        State base = build_state_excluding(curLines, idx);\n\n        if (better_metrics(base.rawScore, base.mass10, base.smallCount,\n                           cur.rawScore, cur.mass10, cur.smallCount) ||\n            same_metrics(base.rawScore, base.mass10, base.smallCount,\n                         cur.rawScore, cur.mass10, cur.smallCount)) {\n            cur = std::move(base);\n            curLines.erase(curLines.begin() + idx);\n            return true;\n        }\n    }\n    return false;\n}\n\nbool retune_pass(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n    bool changed = false;\n\n    vector<int> order(curLines.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int t = 0; t < (int)order.size(); t++) {\n        if (timer.elapsed() >= endTime) break;\n        int idx = order[t];\n        if (idx >= (int)curLines.size()) continue;\n\n        State base = build_state_excluding(curLines, idx);\n        auto n = normalize_pair(curLines[idx].A, curLines[idx].B);\n        auto r = best_line_for_normal(base, n);\n        if (!r.ok) continue;\n\n        if (better_metrics(r.raw, r.mass10, r.small,\n                           cur.rawScore, cur.mass10, cur.smallCount)) {\n            curLines[idx] = r.line;\n            cur = std::move(base);\n            apply_line(cur, r.line);\n            changed = true;\n        }\n    }\n    return changed;\n}\n\nbool replace_once(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n\n    int L = (int)curLines.size();\n    vector<int> candIdx;\n    vector<char> used(L, 0);\n\n    for (int i = max(0, L - 6); i < L; i++) {\n        used[i] = 1;\n        candIdx.push_back(i);\n    }\n    while ((int)candIdx.size() < min(L, 10)) {\n        int x = rng.next_int(0, L - 1);\n        if (!used[x]) {\n            used[x] = 1;\n            candIdx.push_back(x);\n        }\n    }\n\n    int bestIdx = -1;\n    State bestBase;\n    BestLineRes bestMove;\n    bestMove.raw = cur.rawScore;\n    bestMove.mass10 = cur.mass10;\n    bestMove.small = cur.smallCount;\n\n    for (int idx : candIdx) {\n        if (timer.elapsed() >= endTime) break;\n\n        State base = build_state_excluding(curLines, idx);\n\n        // pruning opportunity\n        if (better_metrics(base.rawScore, base.mass10, base.smallCount,\n                           cur.rawScore, cur.mass10, cur.smallCount)) {\n            cur = std::move(base);\n            curLines.erase(curLines.begin() + idx);\n            return true;\n        }\n\n        vector<Line> tempLines;\n        tempLines.reserve(L - 1);\n        for (int i = 0; i < L; i++) if (i != idx) tempLines.push_back(curLines[i]);\n\n        auto cands = make_candidate_normals(base, tempLines, 14);\n        auto oldn = normalize_pair(curLines[idx].A, curLines[idx].B);\n        cands.push_back(oldn);\n        cands.push_back(normalize_pair(-oldn.second, oldn.first));\n        dedup_normals(cands);\n\n        for (auto n : cands) {\n            if (timer.elapsed() >= endTime) break;\n            auto r = best_line_for_normal(base, n);\n            if (!r.ok) continue;\n            if (better_metrics(r.raw, r.mass10, r.small,\n                               bestMove.raw, bestMove.mass10, bestMove.small)) {\n                bestMove = r;\n                bestIdx = idx;\n                bestBase = base;\n            }\n        }\n    }\n\n    if (bestIdx != -1 &&\n        better_metrics(bestMove.raw, bestMove.mass10, bestMove.small,\n                       cur.rawScore, cur.mass10, cur.smallCount)) {\n        curLines[bestIdx] = bestMove.line;\n        cur = std::move(bestBase);\n        apply_line(cur, bestMove.line);\n        return true;\n    }\n    return false;\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = (a >= 0 ? 1 : -1);\n        y = 0;\n        return std::llabs(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\nll modinv(ll a, ll mod) {\n    if (mod == 1) return 0;\n    ll x, y;\n    ll g = extgcd(a, mod, x, y);\n    if (g != 1) return 0;\n    x %= mod;\n    if (x < 0) x += mod;\n    return x;\n}\n\narray<ll,4> line_to_points(const Line& ln) {\n    const ll LIM = 1000000000LL - 5;\n    ll A = ln.A, B = ln.B, C = ln.C;\n\n    if (B == 0) {\n        ll x = C / A;\n        return {x, -LIM, x, LIM};\n    }\n    if (A == 0) {\n        ll y = C / B;\n        return {-LIM, y, LIM, y};\n    }\n\n    ll b = std::llabs(B);\n    ll a = ((A % b) + b) % b;\n    ll c = ((C % b) + b) % b;\n    ll inv = modinv(a, b);\n    ll x0 = (ll)((__int128)inv * c % b);\n    ll y0 = (C - A * x0) / B;\n\n    ll t1 = (LIM - std::llabs(x0)) / std::llabs(B);\n    ll t2 = (LIM - std::llabs(y0)) / std::llabs(A);\n    ll t = min(t1, t2);\n    t = min<ll>(t, 200000);\n    if (t < 1) t = 1;\n\n    ll x1 = x0 - B * t;\n    ll y1 = y0 + A * t;\n    ll x2 = x0 + B * t;\n    ll y2 = y0 - A * t;\n\n    while ((std::llabs(x1) > LIM || std::llabs(y1) > LIM ||\n            std::llabs(x2) > LIM || std::llabs(y2) > LIM) && t > 1) {\n        t /= 2;\n        x1 = x0 - B * t;\n        y1 = y0 + A * t;\n        x2 = x0 + B * t;\n        y2 = y0 - A * t;\n    }\n    return {x1, y1, x2, y2};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    uint64_t seed = 0x123456789abcdef0ull;\n\n    seed ^= splitmix64((uint64_t)N);\n    seed ^= splitmix64((uint64_t)K);\n\n    for (int d = 1; d <= 10; d++) {\n        cin >> a_need[d];\n        attendees_sum += a_need[d];\n        seed ^= splitmix64((uint64_t)(a_need[d] + 1000 * d + 1));\n    }\n\n    pts.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> pts[i].x >> pts[i].y;\n        uint64_t v1 = (uint64_t)(pts[i].x + 20000);\n        uint64_t v2 = (uint64_t)(pts[i].y + 20000);\n        seed ^= splitmix64((v1 << 21) ^ v2 ^ (uint64_t)i * 0x9e3779b97f4a7c15ull);\n    }\n    rng = XorShift64(splitmix64(seed));\n\n    Timer timer;\n\n    const double INITIAL_END = 0.82;\n    const double AUG1_END    = 1.55;\n    const double MID_END     = 2.35;\n    const double REPL_END    = 2.88;\n    const double FINAL_END   = 2.96;\n\n    double lambdaStar = estimate_lambda_star();\n    double lambdaAvg = max(1.0, (double)N / attendees_sum);\n\n    vector<Line> bestLines;\n    State bestState = build_state({});\n    bestLines.clear();\n\n    // deterministic-ish 2-bundle seeds\n    {\n        vector<pair<int,int>> seedNormals = {\n            {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {3,1}, {1,3}\n        };\n        vector<double> lams = {\n            clampv(lambdaStar * 0.85, 1.0, 12.0),\n            clampv(lambdaStar,        1.0, 12.0),\n            clampv(lambdaStar * 1.15, 1.0, 12.0),\n            clampv(lambdaAvg,         1.0, 12.0),\n        };\n        vector<double> alphas = {0.90, 1.00, 1.10};\n        vector<double> offs = {0.0, 0.25};\n\n        for (auto n0 : seedNormals) {\n            auto n = normalize_pair(n0.first, n0.second);\n            for (double lam : lams) {\n                for (double alpha : alphas) {\n                    for (double off : offs) {\n                        Cand2 c;\n                        c.A = n.first;\n                        c.B = n.second;\n                        double Ctarget = N / lam;\n                        double prod = 4.0 * Ctarget / acos(-1.0);\n                        c.t1 = c.t2 = max(1, (int)llround(sqrt(prod) - 1.0));\n                        while (c.t1 + c.t2 > MAX_CUTS) {\n                            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n                            else if (c.t2 > 1) c.t2--;\n                            else break;\n                        }\n                        c.alpha1 = c.alpha2 = alpha;\n                        c.off1 = off;\n                        c.off2 = -off;\n\n                        auto lines = build_lines2(c);\n                        State st = build_state(lines);\n                        if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                            bestState = st;\n                            bestLines = lines;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // random bundled search\n    while (timer.elapsed() < INITIAL_END) {\n        bool use3 = (rng.next() % 10 < 3);\n        if (!use3) {\n            Cand2 c = random_cand2(lambdaStar);\n            int approx = eval_cand2(c);\n            if (approx + 2 >= bestState.rawScore) {\n                auto lines = build_lines2(c);\n                State st = build_state(lines);\n                if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                    bestState = st;\n                    bestLines = lines;\n                }\n            }\n        } else {\n            Cand3 c = random_cand3(lambdaStar);\n            int approx = eval_cand3(c);\n            if (approx + 2 >= bestState.rawScore) {\n                auto lines = build_lines3(c);\n                State st = build_state(lines);\n                if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                    bestState = st;\n                    bestLines = lines;\n                }\n            }\n        }\n    }\n\n    vector<Line> curLines = bestLines;\n    State cur = bestState;\n\n    // phase 1: exact augmentation\n    {\n        int stall = 0;\n        while ((int)curLines.size() < K && timer.elapsed() < AUG1_END && stall < 5 && cur.rawScore < attendees_sum) {\n            int want = (timer.elapsed() < 1.20 ? 28 : 22);\n            bool allowSetup = (stall >= 2);\n            if (try_add_one_exact(cur, curLines, want, allowSetup)) stall = 0;\n            else stall++;\n        }\n    }\n\n    // phase 2: prune + retune coordinate descent\n    while (timer.elapsed() < MID_END) {\n        bool changed = false;\n\n        if (prune_once(cur, curLines, timer, MID_END)) {\n            changed = true;\n            if (timer.elapsed() < MID_END - 0.05 && (int)curLines.size() < K) {\n                try_add_one_exact(cur, curLines, 18, false);\n            }\n            continue;\n        }\n\n        if (retune_pass(cur, curLines, timer, MID_END)) {\n            changed = true;\n        }\n\n        if (!changed) break;\n    }\n\n    // phase 3: replacement neighborhood\n    {\n        int stall = 0;\n        while (timer.elapsed() < REPL_END && stall < 5) {\n            bool changed = replace_once(cur, curLines, timer, REPL_END);\n            if (changed) {\n                stall = 0;\n                if (timer.elapsed() < REPL_END - 0.04 && (int)curLines.size() < K) {\n                    try_add_one_exact(cur, curLines, 16, false);\n                }\n            } else {\n                stall++;\n            }\n        }\n    }\n\n    // final exact augmentation\n    {\n        int stall = 0;\n        while ((int)curLines.size() < K && timer.elapsed() < FINAL_END && stall < 4 && cur.rawScore < attendees_sum) {\n            if (try_add_one_exact(cur, curLines, 18, false)) stall = 0;\n            else stall++;\n        }\n    }\n\n    cout << curLines.size() << '\\n';\n    for (const auto& ln : curLines) {\n        auto p = line_to_points(ln);\n        cout << p[0] << ' ' << p[1] << ' ' << p[2] << ' ' << p[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int MAXID = MAXN * MAXN;\nstatic constexpr int MAXD = 2 * MAXN - 1;\nstatic constexpr double EPS = 1e-12;\n\nint GX[MAXID], GY[MAXID];\ninline int enc(int x, int y) { return y * MAXN + x; }\n\nstruct CoordInit {\n    CoordInit() {\n        for (int y = 0; y < MAXN; ++y) {\n            for (int x = 0; x < MAXN; ++x) {\n                int id = enc(x, y);\n                GX[id] = x;\n                GY[id] = y;\n            }\n        }\n    }\n} coord_init;\n\nstruct Operation {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n};\n\nstruct Candidate {\n    Operation op;\n    double key;\n    int gain;\n    int cost1; // len1 + len2\n    int cost2; // len1^2 + len2^2\n};\n\nstruct Params {\n    double lambda0, lambda1; // linear penalty\n    double quad0, quad1;     // quadratic penalty\n    int topK;\n    int randDepth;\n};\n\nclass Solver {\n    enum Dir {\n        LEFT = 0, RIGHT = 1, DOWN = 2, UP = 3,\n        NE = 4, NW = 5, SW = 6, SE = 7\n    };\n\n    static constexpr int KEEP = 48;\n\n    int N, M, c;\n    int phaseLen;\n\n    vector<int> initialIds;\n    vector<int> cellOrder;\n\n    array<pair<int,int>, 8> pairs{\n        pair<int,int>{LEFT, DOWN},\n        pair<int,int>{LEFT, UP},\n        pair<int,int>{RIGHT, DOWN},\n        pair<int,int>{RIGHT, UP},\n        pair<int,int>{NE, NW},\n        pair<int,int>{NE, SE},\n        pair<int,int>{SW, NW},\n        pair<int,int>{SW, SE}\n    };\n\n    int weight[MAXN][MAXN]{};\n\n    unsigned char dot[MAXN][MAXN]{};\n    unsigned char useH[MAXN - 1][MAXN]{};\n    unsigned char useV[MAXN][MAXN - 1]{};\n    unsigned char useD1[MAXN - 1][MAXN - 1]{};\n    unsigned char useD2[MAXN - 1][MAXN - 1]{};\n\n    int nearDot[8][MAXN][MAXN]{};\n\n    int prefH[MAXN][MAXN + 1]{};\n    int prefV[MAXN][MAXN + 1]{};\n    int prefD1[MAXD][MAXN + 1]{};\n    int prefD2[MAXD][MAXN + 1]{};\n\n    long long initialWeight = 0;\n    long long curWeight = 0;\n    long long bestWeight = 0;\n\n    vector<Operation> ops;\n    vector<Operation> bestOps;\n\n    mt19937_64 rng;\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    static bool betterCand(const Candidate& a, const Candidate& b) {\n        if (a.key > b.key + EPS) return true;\n        if (a.key + EPS < b.key) return false;\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.cost2 != b.cost2) return a.cost2 < b.cost2;\n        if (a.cost1 != b.cost1) return a.cost1 < b.cost1;\n        return false;\n    }\n\n    void consider(vector<Candidate>& top, const Candidate& cand, int keep) {\n        int pos = (int)top.size();\n        while (pos > 0 && betterCand(cand, top[pos - 1])) --pos;\n        if (pos >= keep) return;\n        top.insert(top.begin() + pos, cand);\n        if ((int)top.size() > keep) top.pop_back();\n    }\n\n    int chooseIndex(int lim) {\n        if (lim <= 1) return 0;\n        uint64_t sum = (uint64_t)lim * (lim + 1) / 2;\n        uint64_t r = rng() % sum;\n        uint64_t acc = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (uint64_t)(lim - i);\n            if (r < acc) return i;\n        }\n        return 0;\n    }\n\n    void resetState() {\n        memset(dot, 0, sizeof(dot));\n        memset(useH, 0, sizeof(useH));\n        memset(useV, 0, sizeof(useV));\n        memset(useD1, 0, sizeof(useD1));\n        memset(useD2, 0, sizeof(useD2));\n        for (int id : initialIds) {\n            dot[GX[id]][GY[id]] = 1;\n        }\n        curWeight = initialWeight;\n        ops.clear();\n    }\n\n    void recomputeAux() {\n        // rows\n        for (int y = 0; y < N; ++y) {\n            int last = -1;\n            for (int x = 0; x < N; ++x) {\n                nearDot[LEFT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int x = N - 1; x >= 0; --x) {\n                nearDot[RIGHT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // columns\n        for (int x = 0; x < N; ++x) {\n            int last = -1;\n            for (int y = 0; y < N; ++y) {\n                nearDot[DOWN][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int y = N - 1; y >= 0; --y) {\n                nearDot[UP][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // main diagonals: x - y = const\n        for (int d = -(N - 1); d <= (N - 1); ++d) {\n            int minx = max(0, d);\n            int maxx = min(N - 1, N - 1 + d);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = x - d;\n                nearDot[SW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = x - d;\n                nearDot[NE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // anti-diagonals: x + y = const\n        for (int s = 0; s <= 2 * (N - 1); ++s) {\n            int minx = max(0, s - (N - 1));\n            int maxx = min(N - 1, s);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = s - x;\n                nearDot[NW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = s - x;\n                nearDot[SE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // prefix sums for used segments\n        for (int y = 0; y < N; ++y) {\n            prefH[y][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int add = (x < N - 1 ? useH[x][y] : 0);\n                prefH[y][x + 1] = prefH[y][x] + add;\n            }\n        }\n\n        for (int x = 0; x < N; ++x) {\n            prefV[x][0] = 0;\n            for (int y = 0; y < N; ++y) {\n                int add = (y < N - 1 ? useV[x][y] : 0);\n                prefV[x][y + 1] = prefV[x][y] + add;\n            }\n        }\n\n        for (int didx = 0; didx < 2 * N - 1; ++didx) {\n            int d = didx - (N - 1);\n            prefD1[didx][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = x - d;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD1[x][y];\n                prefD1[didx][x + 1] = prefD1[didx][x] + add;\n            }\n        }\n\n        for (int s = 0; s < 2 * N - 1; ++s) {\n            prefD2[s][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = s - x - 1;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD2[x][y];\n                prefD2[s][x + 1] = prefD2[s][x] + add;\n            }\n        }\n    }\n\n    int usedCountOnSegment(int x1, int y1, int x2, int y2) const {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefH[y1][r] - prefH[y1][l];\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            return prefV[x1][r] - prefV[x1][l];\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + (N - 1);\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD1[d][r] - prefD1[d][l];\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD2[s][r] - prefD2[s][l];\n        }\n    }\n\n    void markSegment(int x1, int y1, int x2, int y2) {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) useH[x][y1] = 1;\n            return;\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            for (int y = l; y < r; ++y) useV[x1][y] = 1;\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = x - d;\n                useD1[x][y] = 1;\n            }\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = s - x - 1;\n                useD2[x][y] = 1;\n            }\n        }\n    }\n\n    void apply(const Candidate& cand) {\n        const auto& o = cand.op;\n        dot[o.x1][o.y1] = 1;\n        curWeight += weight[o.x1][o.y1];\n\n        markSegment(o.x1, o.y1, o.x2, o.y2);\n        markSegment(o.x2, o.y2, o.x3, o.y3);\n        markSegment(o.x3, o.y3, o.x4, o.y4);\n        markSegment(o.x4, o.y4, o.x1, o.y1);\n\n        ops.push_back(o);\n    }\n\n    double interp(double a, double b, int step) const {\n        if (step >= phaseLen) return b;\n        double t = double(phaseLen - step) / phaseLen;\n        return b + (a - b) * t;\n    }\n\n    vector<Candidate> collectTop(double lambda, double quad, int keep) {\n        vector<Candidate> top;\n        top.reserve(keep);\n\n        for (int id1 : cellOrder) {\n            int x = GX[id1], y = GY[id1];\n            if (dot[x][y]) continue;\n\n            int gain = weight[x][y];\n            if ((int)top.size() == keep) {\n                double upper = gain - lambda * 2.0 - quad * 2.0; // len1=len2=1\n                if (upper + EPS < top.back().key) break;\n            }\n\n            for (auto [da, db] : pairs) {\n                int id2 = nearDot[da][x][y];\n                if (id2 < 0) continue;\n                int id4 = nearDot[db][x][y];\n                if (id4 < 0) continue;\n\n                int x2 = GX[id2], y2 = GY[id2];\n                int x4 = GX[id4], y4 = GY[id4];\n\n                int x3 = x2 + x4 - x;\n                int y3 = y2 + y4 - y;\n                if (!inside(x3, y3)) continue;\n                if (!dot[x3][y3]) continue;\n\n                int id3 = enc(x3, y3);\n\n                // no other dots on perimeter\n                if (nearDot[db][x2][y2] != id3) continue;\n                if (nearDot[da][x4][y4] != id3) continue;\n\n                // no positive-length overlap with already drawn segments\n                if (usedCountOnSegment(x, y, x2, y2)) continue;\n                if (usedCountOnSegment(x2, y2, x3, y3)) continue;\n                if (usedCountOnSegment(x3, y3, x4, y4)) continue;\n                if (usedCountOnSegment(x4, y4, x, y)) continue;\n\n                int len1 = max(abs(x2 - x), abs(y2 - y));\n                int len2 = max(abs(x4 - x), abs(y4 - y));\n                int cost1 = len1 + len2;\n                int cost2 = len1 * len1 + len2 * len2;\n\n                Candidate cand{\n                    Operation{x, y, x2, y2, x3, y3, x4, y4},\n                    gain - lambda * cost1 - quad * cost2,\n                    gain,\n                    cost1,\n                    cost2\n                };\n                consider(top, cand, keep);\n            }\n        }\n\n        return top;\n    }\n\n    void runAttempt(const Params& prm,\n                    chrono::steady_clock::time_point deadline,\n                    const vector<int>& forcedRanks = {}) {\n        resetState();\n        int step = 0;\n\n        while (true) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            recomputeAux();\n            double lambda = interp(prm.lambda0, prm.lambda1, step);\n            double quad = interp(prm.quad0, prm.quad1, step);\n            auto top = collectTop(lambda, quad, KEEP);\n            if (top.empty()) break;\n\n            int idx = 0;\n            if (step < (int)forcedRanks.size()) {\n                idx = min(forcedRanks[step], (int)top.size() - 1);\n            } else if (step < prm.randDepth && prm.topK > 1) {\n                idx = chooseIndex(min(prm.topK, (int)top.size()));\n            }\n\n            apply(top[idx]);\n            ++step;\n        }\n\n        if (curWeight > bestWeight) {\n            bestWeight = curWeight;\n            bestOps = ops;\n        }\n    }\n\n    int rootTopCount(const Params& prm, int cap) {\n        resetState();\n        recomputeAux();\n        auto top = collectTop(interp(prm.lambda0, prm.lambda1, 0),\n                              interp(prm.quad0, prm.quad1, 0),\n                              cap);\n        return (int)top.size();\n    }\n\npublic:\n    Solver(int N_, int M_, const vector<pair<int,int>>& pts) : N(N_), M(M_), c((N_ - 1) / 2) {\n        phaseLen = max(18, min(40, N));\n\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)N * 1000003ULL;\n        seed ^= (uint64_t)M * 10007ULL;\n        for (auto [x, y] : pts) {\n            seed ^= (uint64_t)(x + 1) * 911382323ULL;\n            seed ^= (uint64_t)(y + 7) * 972663749ULL;\n        }\n        rng.seed(seed);\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                weight[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n                cellOrder.push_back(enc(x, y));\n            }\n        }\n\n        stable_sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n            int xa = GX[a], ya = GY[a];\n            int xb = GX[b], yb = GY[b];\n            if (weight[xa][ya] != weight[xb][yb]) return weight[xa][ya] > weight[xb][yb];\n            int ma = max(abs(xa - c), abs(ya - c));\n            int mb = max(abs(xb - c), abs(yb - c));\n            if (ma != mb) return ma > mb;\n            int sa = abs(xa - c) + abs(ya - c);\n            int sb = abs(xb - c) + abs(yb - c);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n\n        for (auto [x, y] : pts) {\n            int id = enc(x, y);\n            initialIds.push_back(id);\n            initialWeight += weight[x][y];\n        }\n\n        curWeight = bestWeight = initialWeight;\n        ops.reserve(N * N);\n        bestOps.reserve(N * N);\n    }\n\n    void solve() {\n        auto start = chrono::steady_clock::now();\n        auto deadline = start + chrono::milliseconds(4700);\n\n        // Fast deterministic baselines (close to the best earlier version)\n        vector<Params> fixed = {\n            {20.0, 20.0, 0.0, 0.0, 1, 0},\n            {12.0, 12.0, 0.0, 0.0, 1, 0},\n            { 8.0,  8.0, 0.0, 0.0, 1, 0},\n            { 4.0,  4.0, 0.0, 0.0, 1, 0},\n            { 2.0,  2.0, 0.0, 0.0, 1, 0},\n            { 1.0,  1.0, 0.0, 0.0, 1, 0},\n            { 0.5,  0.5, 0.0, 0.0, 1, 0},\n            { 0.0,  0.0, 0.0, 0.0, 1, 0},\n\n            {12.0,  2.0, 0.0, 0.0, 1, 0},\n            { 8.0,  1.0, 0.0, 0.0, 1, 0},\n            { 4.0,  0.0, 0.0, 0.0, 1, 0},\n            { 2.0,  0.0, 0.0, 0.0, 1, 0},\n\n            // tiny quadratic penalty in a few attempts only\n            { 8.0,  1.0, 0.10, 0.00, 1, 0},\n            { 4.0,  0.0, 0.15, 0.00, 1, 0},\n\n            { 4.0,  0.0, 0.0, 0.0, 4, 10},\n            { 2.0,  0.0, 0.0, 0.0, 6, 16},\n            { 1.0,  0.0, 0.0, 0.0, 8, 24},\n            { 0.5,  0.0, 0.0, 0.0,10, 32},\n            { 0.0,  0.0, 0.0, 0.0,10, 40}\n        };\n\n        for (const auto& prm : fixed) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            runAttempt(prm, deadline);\n        }\n\n        // Lightweight systematic diversification on first move\n        vector<Params> prefixParams = {\n            {8.0, 1.0, 0.0, 0.0, 1, 0},\n            {4.0, 0.0, 0.0, 0.0, 1, 0},\n            {2.0, 0.0, 0.0, 0.0, 1, 0}\n        };\n\n        for (const auto& prm : prefixParams) {\n            if (chrono::steady_clock::now() + chrono::milliseconds(120) >= deadline) break;\n            int cnt = rootTopCount(prm, 6);\n            for (int r = 0; r < cnt; ++r) {\n                if (chrono::steady_clock::now() + chrono::milliseconds(60) >= deadline) break;\n                runAttempt(prm, deadline, {r});\n            }\n        }\n\n        // Very small two-move prefix exploration\n        {\n            Params prm{4.0, 0.0, 0.0, 0.0, 1, 0};\n            if (chrono::steady_clock::now() + chrono::milliseconds(160) < deadline) {\n                for (int r1 = 0; r1 < 3; ++r1) {\n                    for (int r2 = 0; r2 < 2; ++r2) {\n                        if (chrono::steady_clock::now() + chrono::milliseconds(60) >= deadline) break;\n                        runAttempt(prm, deadline, {r1, r2});\n                    }\n                }\n            }\n        }\n\n        static const vector<double> L0 = {0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 12.0, 16.0, 20.0};\n        static const vector<double> L1 = {0.0, 0.0, 0.25, 0.5, 1.0, 2.0};\n        static const vector<double> Q0 = {0.0, 0.0, 0.0, 0.05, 0.10, 0.15, 0.20};\n        static const vector<int> TK = {1, 2, 3, 4, 6, 8, 10, 12};\n        static const vector<int> RD = {0, 4, 8, 12, 16, 24, 32, 48, 64};\n\n        while (chrono::steady_clock::now() < deadline) {\n            Params prm;\n            prm.lambda0 = L0[(size_t)(rng() % L0.size())];\n            prm.lambda1 = L1[(size_t)(rng() % L1.size())];\n            if (prm.lambda1 > prm.lambda0) swap(prm.lambda0, prm.lambda1);\n\n            prm.quad0 = Q0[(size_t)(rng() % Q0.size())];\n            prm.quad1 = 0.0;\n            if ((rng() & 3ULL) == 0) prm.quad0 = 0.0; // often pure baseline\n\n            prm.topK = TK[(size_t)(rng() % TK.size())];\n            prm.randDepth = RD[(size_t)(rng() % RD.size())];\n            if (prm.topK == 1) prm.randDepth = 0;\n\n            uint64_t mode = rng() & 31ULL;\n            if (mode == 0) {\n                runAttempt(prm, deadline, {(int)(rng() % 6)});\n            } else if (mode == 1) {\n                runAttempt(prm, deadline, {(int)(rng() % 4), (int)(rng() % 3)});\n            } else {\n                runAttempt(prm, deadline);\n            }\n        }\n    }\n\n    void output() const {\n        cout << bestOps.size() << '\\n';\n        for (const auto& o : bestOps) {\n            cout << o.x1 << ' ' << o.y1 << ' '\n                 << o.x2 << ' ' << o.y2 << ' '\n                 << o.x3 << ' ' << o.y3 << ' '\n                 << o.x4 << ' ' << o.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<pair<int,int>> pts(M);\n    for (int i = 0; i < M; ++i) {\n        cin >> pts[i].first >> pts[i].second;\n    }\n\n    Solver solver(N, M, pts);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Board {\n    array<uint8_t, 100> a;\n};\n\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'}; // F: up, B: down, L: left, R: right\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nstruct Analysis {\n    int compSq = 0;\n    int largest[4] = {};\n    int compCnt[4] = {};\n    int sameAdj = 0;\n    int diffAdj = 0;\n    int patternPenalty = 0;\n};\n\nclass Solver {\n    static constexpr double TIME_LIMIT = 1.78;\n\n    int flavor[101]{};\n    int totalCnt[4]{};\n    int suffixCnt[103][4]{};\n\n    Board cur{};\n    SplitMix64 rng;\n    chrono::steady_clock::time_point st;\n\n    int perms[6][3] = {\n        {1,2,3}, {1,3,2}, {2,1,3},\n        {2,3,1}, {3,1,2}, {3,2,1}\n    };\n\n    uint8_t pathCell[8][100]{};\n    uint8_t distCost[48][100][4]{}; // [pattern][cell][color]\n    int lastPattern = -1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    static inline void place_by_rank(Board &b, int rank, int f) {\n        for (int i = 0; i < 100; ++i) {\n            if (b.a[i] == 0) {\n                if (--rank == 0) {\n                    b.a[i] = (uint8_t)f;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline void apply_tilt(const Board &src, int dir, Board &dst) {\n        dst.a.fill(0);\n        if (dir == 0) { // F = up\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 0;\n                for (int r = 0; r < 10; ++r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[(ptr++) * 10 + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B = down\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 9;\n                for (int r = 9; r >= 0; --r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[(ptr--) * 10 + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L = left\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 0;\n                for (int c = 0; c < 10; ++c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + (ptr++)] = v;\n                }\n            }\n        } else { // R = right\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 9;\n                for (int c = 9; c >= 0; --c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + (ptr--)] = v;\n                }\n            }\n        }\n    }\n\n    static int comp_sq_only(const Board &b) {\n        uint8_t vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    Analysis analyze(const Board &b, int activePattern) const {\n        Analysis e;\n\n        for (int r = 0; r < 10; ++r) {\n            for (int c = 0; c < 10; ++c) {\n                int id = r * 10 + c;\n                uint8_t col = b.a[id];\n                if (!col) continue;\n\n                e.patternPenalty += distCost[activePattern][id][col];\n\n                if (c + 1 < 10 && b.a[id + 1]) {\n                    if (b.a[id + 1] == col) e.sameAdj++;\n                    else e.diffAdj++;\n                }\n                if (r + 1 < 10 && b.a[id + 10]) {\n                    if (b.a[id + 10] == col) e.sameAdj++;\n                    else e.diffAdj++;\n                }\n            }\n        }\n\n        uint8_t vis[100] = {};\n        int q[100];\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n\n            e.compSq += sz * sz;\n            e.largest[col] = max(e.largest[col], sz);\n            e.compCnt[col]++;\n        }\n\n        return e;\n    }\n\n    long long heuristic(const Board &b, int step, int activePattern) const {\n        Analysis e = analyze(b, activePattern);\n\n        long long optimistic = e.compSq;\n        long long futureFragPenalty = 0;\n        int curFragments = 0;\n\n        for (int c = 1; c <= 3; ++c) {\n            int rem = suffixCnt[step + 1][c];\n            optimistic += 2LL * e.largest[c] * rem;\n            futureFragPenalty += 1LL * max(0, e.compCnt[c] - 1) * rem;\n            curFragments += max(0, e.compCnt[c] - 1);\n        }\n\n        long long wPat = 22 + step / 3;\n\n        return optimistic * 1000LL\n             - futureFragPenalty * 210LL\n             - 110LL * curFragments * curFragments\n             + 48LL * e.sameAdj\n             - 32LL * e.diffAdj\n             - wPat * e.patternPenalty;\n    }\n\n    int pattern_penalty(const Board &b, int pat) const {\n        int sum = 0;\n        for (int i = 0; i < 100; ++i) {\n            uint8_t col = b.a[i];\n            if (col) sum += distCost[pat][i][col];\n        }\n        return sum;\n    }\n\n    int select_active_pattern(const Board cand[4]) {\n        int bestPat = 0;\n        int bestScore = INT_MAX;\n\n        for (int pat = 0; pat < 48; ++pat) {\n            int s = 0;\n            for (int d = 0; d < 4; ++d) s += pattern_penalty(cand[d], pat);\n            if (s < bestScore) {\n                bestScore = s;\n                bestPat = pat;\n            }\n        }\n\n        if (lastPattern != -1) {\n            int prevScore = 0;\n            for (int d = 0; d < 4; ++d) prevScore += pattern_penalty(cand[d], lastPattern);\n            if (prevScore <= bestScore + 8) return lastPattern;\n        }\n        return bestPat;\n    }\n\n    double exact_expect(const Board &state_after_tilt, int step) {\n        int next = step + 1;\n        int holes = 101 - next;\n        double sum = 0.0;\n\n        for (int rank = 1; rank <= holes; ++rank) {\n            Board b = state_after_tilt;\n            place_by_rank(b, rank, flavor[next]);\n\n            if (next == 100) {\n                sum += comp_sq_only(b);\n            } else {\n                double best = -1e100;\n                Board tmp;\n                for (int d = 0; d < 4; ++d) {\n                    apply_tilt(b, d, tmp);\n                    best = max(best, exact_expect(tmp, next));\n                }\n                sum += best;\n            }\n        }\n        return sum / holes;\n    }\n\n    int greedy_best_dir(const Board &after_insert, int step, int activePattern, Board &best_board_out) const {\n        long long bestH = LLONG_MIN;\n        int bestD = 0;\n        Board tmp;\n        for (int d = 0; d < 4; ++d) {\n            apply_tilt(after_insert, d, tmp);\n            long long h = heuristic(tmp, step, activePattern);\n            if (h > bestH) {\n                bestH = h;\n                bestD = d;\n                best_board_out = tmp;\n            }\n        }\n        return bestD;\n    }\n\n    void init_patterns() {\n        int pid = 0;\n\n        // 4 row snakes\n        for (int fv = 0; fv < 2; ++fv) {\n            for (int fh = 0; fh < 2; ++fh) {\n                int k = 0;\n                for (int r = 0; r < 10; ++r) {\n                    if ((r & 1) == 0) {\n                        for (int c = 0; c < 10; ++c) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    } else {\n                        for (int c = 9; c >= 0; --c) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    }\n                }\n                ++pid;\n            }\n        }\n\n        // 4 col snakes\n        for (int fv = 0; fv < 2; ++fv) {\n            for (int fh = 0; fh < 2; ++fh) {\n                int k = 0;\n                for (int c = 0; c < 10; ++c) {\n                    if ((c & 1) == 0) {\n                        for (int r = 0; r < 10; ++r) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    } else {\n                        for (int r = 9; r >= 0; --r) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    }\n                }\n                ++pid;\n            }\n        }\n\n        for (int p = 0; p < 8; ++p) {\n            for (int q = 0; q < 6; ++q) {\n                int pat = p * 6 + q;\n                int L[4] = {}, R[4] = {};\n                int curPos = 0;\n                for (int t = 0; t < 3; ++t) {\n                    int c = perms[q][t];\n                    if (totalCnt[c] == 0) {\n                        L[c] = 0;\n                        R[c] = -1;\n                    } else {\n                        L[c] = curPos;\n                        R[c] = curPos + totalCnt[c] - 1;\n                        curPos += totalCnt[c];\n                    }\n                }\n\n                for (int idx = 0; idx < 100; ++idx) {\n                    int cell = pathCell[p][idx];\n                    for (int c = 1; c <= 3; ++c) {\n                        int dist = 0;\n                        if (totalCnt[c] == 0) dist = 0;\n                        else if (idx < L[c]) dist = L[c] - idx;\n                        else if (idx > R[c]) dist = idx - R[c];\n                        else dist = 0;\n                        distCost[pat][cell][c] = (uint8_t)dist;\n                    }\n                }\n            }\n        }\n    }\n\n    int choose_dir(const Board &after_insert, int step) {\n        if (step == 100) return 0;\n\n        Board first[4];\n        for (int d = 0; d < 4; ++d) apply_tilt(after_insert, d, first[d]);\n\n        int activePattern = select_active_pattern(first);\n        lastPattern = activePattern;\n\n        long long baseH[4];\n        for (int d = 0; d < 4; ++d) baseH[d] = heuristic(first[d], step, activePattern);\n\n        int greedyBest = 0;\n        for (int d = 1; d < 4; ++d) {\n            if (baseH[d] > baseH[greedyBest]) greedyBest = d;\n        }\n\n        if (elapsed() > TIME_LIMIT - 0.03) return greedyBest;\n\n        int rem = 100 - step;\n\n        // Exact endgame.\n        if (rem <= 5 && elapsed() < TIME_LIMIT - 0.03) {\n            double bestVal = -1e100;\n            int bestD = greedyBest;\n            for (int d = 0; d < 4; ++d) {\n                if (elapsed() > TIME_LIMIT - 0.02) break;\n                double v = exact_expect(first[d], step);\n                if (v > bestVal + 1e-12 || (fabs(v - bestVal) <= 1e-12 && baseH[d] > baseH[bestD])) {\n                    bestVal = v;\n                    bestD = d;\n                }\n            }\n            return bestD;\n        }\n\n        // Common-random-number rollouts.\n        int K = min(16, max(4, 300 / max(1, rem)));\n        double left = TIME_LIMIT - elapsed();\n        if (left < 0.35) K = max(4, K / 2);\n        if (left < 0.18) K = 2;\n\n        long long sumFinal[4] = {};\n        int done = 0;\n        int ranks[101];\n        Board sim, nextBestBoard;\n\n        for (int k = 0; k < K; ++k) {\n            if (elapsed() > TIME_LIMIT - 0.02) break;\n\n            for (int u = step + 1; u <= 100; ++u) {\n                ranks[u] = 1 + rng.next_int(101 - u);\n            }\n\n            for (int d = 0; d < 4; ++d) {\n                if (elapsed() > TIME_LIMIT - 0.02) break;\n\n                sim = first[d];\n                for (int u = step + 1; u <= 100; ++u) {\n                    place_by_rank(sim, ranks[u], flavor[u]);\n                    if (u == 100) break;\n                    greedy_best_dir(sim, u, activePattern, nextBestBoard);\n                    sim = nextBestBoard;\n                }\n                sumFinal[d] += comp_sq_only(sim);\n            }\n            ++done;\n        }\n\n        if (done == 0) return greedyBest;\n\n        double bestScore = -1e100;\n        int bestD = greedyBest;\n        for (int d = 0; d < 4; ++d) {\n            double avgFinal = (double)sumFinal[d] / done;\n            double score = avgFinal * 3000.0 + (double)baseH[d];\n            if (score > bestScore) {\n                bestScore = score;\n                bestD = d;\n            }\n        }\n        return bestD;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 1; i <= 100; ++i) {\n            cin >> flavor[i];\n            totalCnt[flavor[i]]++;\n        }\n\n        for (int c = 1; c <= 3; ++c) suffixCnt[101][c] = 0;\n        for (int t = 100; t >= 1; --t) {\n            for (int c = 1; c <= 3; ++c) suffixCnt[t][c] = suffixCnt[t + 1][c];\n            suffixCnt[t][flavor[t]]++;\n        }\n\n        init_patterns();\n\n        uint64_t seed = 0x123456789abcdefULL;\n        for (int i = 1; i <= 100; ++i) {\n            seed = seed * 6364136223846793005ULL + (uint64_t)(flavor[i] + 1);\n        }\n        rng = SplitMix64(seed);\n\n        cur.a.fill(0);\n        st = chrono::steady_clock::now();\n\n        for (int t = 1; t <= 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place_by_rank(cur, p, flavor[t]);\n\n            int d = choose_dir(cur, t);\n\n            Board nxt;\n            apply_tilt(cur, d, nxt);\n            cur = nxt;\n\n            cout << DIR_CH[d] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\n\n// ------------------------------------------------------------\n// Utility\n// ------------------------------------------------------------\n\nstatic inline long long C2(long long n) { return (n >= 2 ? n * (n - 1) / 2 : 0); }\nstatic inline long long C3(long long n) { return (n >= 3 ? n * (n - 1) * (n - 2) / 6 : 0); }\n\nstatic double expected_score_from_err_rate(double p_err, int N) {\n    p_err = max(0.0, min(1.0, p_err));\n    return pow(0.9, 100.0 * p_err) / N;\n}\nstatic double score_from_counts(int err, int tot, int N) {\n    double p = (err + 0.5) / (tot + 1.0); // mild smoothing\n    return expected_score_from_err_rate(p, N);\n}\n\nstatic vector<int> sample_ids_evenly(int M, int S) {\n    S = min(S, M);\n    vector<int> ids;\n    ids.reserve(S);\n    for (int t = 0; t < S; t++) {\n        int id = (long long)t * M / S;\n        if (ids.empty() || ids.back() != id) ids.push_back(id);\n    }\n    if ((int)ids.size() < S) {\n        vector<char> used(M, 0);\n        for (int x : ids) used[x] = 1;\n        for (int i = 0; i < M && (int)ids.size() < S; i++) {\n            if (!used[i]) ids.push_back(i);\n        }\n        sort(ids.begin(), ids.end());\n    }\n    return ids;\n}\n\n// ------------------------------------------------------------\n// Small exact / low-noise strategy (N<=6)\n// ------------------------------------------------------------\n\nstruct SmallDB {\n    int N = 0, E = 0, maskCnt = 0, P = 0;\n    vector<pair<int,int>> edges;\n    vector<uint16_t> reps;                    // canonical representatives\n    vector<vector<uint16_t>> repPermMasks;    // all unique permuted masks per representative\n    vector<vector<uint8_t>> dist;             // exact unlabeled edit distance between reps\n    vector<vector<int>> permMaps;\n};\n\nstatic SmallDB init_small_db(int N) {\n    SmallDB db;\n    db.N = N;\n    int edgeIndex[8][8];\n    memset(edgeIndex, -1, sizeof(edgeIndex));\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            edgeIndex[i][j] = edgeIndex[j][i] = (int)db.edges.size();\n            db.edges.push_back({i, j});\n        }\n    }\n    db.E = (int)db.edges.size();\n    db.maskCnt = 1 << db.E;\n\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n    do {\n        vector<int> mp(db.E);\n        for (int e = 0; e < db.E; e++) {\n            auto [u, v] = db.edges[e];\n            int a = perm[u], b = perm[v];\n            if (a > b) swap(a, b);\n            mp[e] = edgeIndex[a][b];\n        }\n        db.permMaps.push_back(std::move(mp));\n    } while (next_permutation(perm.begin(), perm.end()));\n    db.P = (int)db.permMaps.size();\n\n    vector<uint16_t> permTable((size_t)db.P * db.maskCnt);\n    for (int p = 0; p < db.P; p++) {\n        size_t base = (size_t)p * db.maskCnt;\n        permTable[base] = 0;\n        for (int mask = 1; mask < db.maskCnt; mask++) {\n            int lb = mask & -mask;\n            int bit = __builtin_ctz(lb);\n            int prev = mask ^ lb;\n            permTable[base + mask] = permTable[base + prev] | (uint16_t(1) << db.permMaps[p][bit]);\n        }\n    }\n\n    vector<char> seen(db.maskCnt, 0);\n    for (int mask = 0; mask < db.maskCnt; mask++) {\n        uint16_t best = numeric_limits<uint16_t>::max();\n        for (int p = 0; p < db.P; p++) {\n            uint16_t x = permTable[(size_t)p * db.maskCnt + mask];\n            if (x < best) best = x;\n        }\n        if (!seen[best]) {\n            seen[best] = 1;\n            db.reps.push_back(best);\n        }\n    }\n    sort(db.reps.begin(), db.reps.end());\n\n    int C = (int)db.reps.size();\n    db.repPermMasks.resize(C);\n    for (int i = 0; i < C; i++) {\n        uint16_t rep = db.reps[i];\n        auto &vv = db.repPermMasks[i];\n        vv.reserve(db.P);\n        for (int p = 0; p < db.P; p++) {\n            vv.push_back(permTable[(size_t)p * db.maskCnt + rep]);\n        }\n        sort(vv.begin(), vv.end());\n        vv.erase(unique(vv.begin(), vv.end()), vv.end());\n    }\n\n    db.dist.assign(C, vector<uint8_t>(C, 0));\n    for (int i = 0; i < C; i++) {\n        for (int j = i + 1; j < C; j++) {\n            int best = db.E + 1;\n            for (uint16_t pm : db.repPermMasks[j]) {\n                int d = __builtin_popcount((unsigned)(db.reps[i] ^ pm));\n                if (d < best) best = d;\n                if (best == 0) break;\n            }\n            db.dist[i][j] = db.dist[j][i] = (uint8_t)best;\n        }\n    }\n    return db;\n}\n\nstatic uint16_t canonicalize_small(const SmallDB& db, uint16_t mask) {\n    uint16_t best = numeric_limits<uint16_t>::max();\n    for (int p = 0; p < db.P; p++) {\n        uint16_t y = 0;\n        for (int b = 0; b < db.E; b++) {\n            if ((mask >> b) & 1) y |= (uint16_t(1) << db.permMaps[p][b]);\n        }\n        if (y < best) best = y;\n    }\n    return best;\n}\n\nstatic string small_mask_to_string(uint16_t mask, int E) {\n    string s(E, '0');\n    for (int i = 0; i < E; i++) if ((mask >> i) & 1) s[i] = '1';\n    return s;\n}\n\nstatic double small_selection_quality(const SmallDB& db, const vector<int>& sel) {\n    if (sel.size() <= 1) return 0.0;\n    double sum = 0;\n    for (int i = 0; i < (int)sel.size(); i++) {\n        int best = 1e9;\n        for (int j = 0; j < (int)sel.size(); j++) if (i != j) {\n            best = min(best, (int)db.dist[sel[i]][sel[j]]);\n        }\n        sum += best;\n    }\n    return sum / sel.size();\n}\n\nstatic vector<int> select_small_code_indices(const SmallDB& db, int M) {\n    int C = (int)db.reps.size();\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        int ea = __builtin_popcount((unsigned)db.reps[a]);\n        int eb = __builtin_popcount((unsigned)db.reps[b]);\n        if (ea != eb) return ea < eb;\n        return db.reps[a] < db.reps[b];\n    });\n\n    if (C <= M) return idx;\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2], idx[C / 3], idx[(2 * C) / 3]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQ = -1;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<int> minDist(C, 1e9);\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                minDist[i] = min(minDist[i], (int)db.dist[x][i]);\n            }\n        };\n\n        add_one(seed);\n        while ((int)sel.size() < M) {\n            int nxt = -1, best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double q = small_selection_quality(db, sel);\n        if (q > bestQ) {\n            bestQ = q;\n            bestSel = sel;\n        }\n    }\n\n    sort(bestSel.begin(), bestSel.end(), [&](int a, int b) {\n        int ea = __builtin_popcount((unsigned)db.reps[a]);\n        int eb = __builtin_popcount((unsigned)db.reps[b]);\n        if (ea != eb) return ea < eb;\n        return db.reps[a] < db.reps[b];\n    });\n    return bestSel;\n}\n\nstruct SmallStrategy {\n    int N = 0, E = 0, M = 0;\n    vector<uint16_t> codeMasks;\n    vector<vector<uint16_t>> codePermMasks;\n    vector<string> graphStrs;\n    double estScore = -1;\n};\n\nstatic int decode_small(const SmallStrategy& st, uint16_t mask) {\n    int bestId = 0;\n    int bestDist = st.E + 1;\n    for (int i = 0; i < st.M; i++) {\n        int curBest = st.E + 1;\n        for (uint16_t pm : st.codePermMasks[i]) {\n            int d = __builtin_popcount((unsigned)(mask ^ pm));\n            if (d < curBest) curBest = d;\n            if (curBest == 0) break;\n        }\n        if (curBest < bestDist) {\n            bestDist = curBest;\n            bestId = i;\n        }\n    }\n    return bestId;\n}\n\nstatic double estimate_small_strategy(SmallStrategy& st, double eps, int reps, uint64_t seed) {\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    int err = 0, tot = 0;\n    for (int i = 0; i < st.M; i++) {\n        uint16_t base = st.codeMasks[i];\n        for (int r = 0; r < reps; r++) {\n            uint16_t noisy = base;\n            for (int b = 0; b < st.E; b++) {\n                if (ur(rng) < eps) noisy ^= (uint16_t(1) << b);\n            }\n            int ans = decode_small(st, noisy);\n            if (ans != i) err++;\n            tot++;\n        }\n    }\n    return score_from_counts(err, tot, st.N);\n}\n\n// ------------------------------------------------------------\n// Large robust families\n// ------------------------------------------------------------\n\nenum FamilyType {\n    F_PARTITION = 0,\n    F_THRESHOLD_INDEP = 1,\n    F_THRESHOLD_CLIQUE = 2\n};\n\nstruct BaseCand {\n    int family = 0;\n    int B = 0;\n\n    // partition family\n    vector<int> parts; // ascending\n    int type = 0;      // 0=union of cliques, 1=complete multipartite\n\n    // threshold family\n    uint32_t mask = 0; // bits for vertices 1..B-1: 1=dominating, 0=isolated\n\n    vector<int> degBaseSorted; // length B\n    int edgeBase = 0;\n};\n\nstatic void gen_partitions_rec(int rem, int last, bool distinctOnly, vector<int>& cur, vector<vector<int>>& out) {\n    if (rem == 0) {\n        out.push_back(cur);\n        return;\n    }\n    for (int x = last; x <= rem; x++) {\n        cur.push_back(x);\n        gen_partitions_rec(rem - x, distinctOnly ? x + 1 : x, distinctOnly, cur, out);\n        cur.pop_back();\n    }\n}\n\nstatic vector<vector<int>> generate_partitions(int B, bool distinctOnly) {\n    vector<vector<int>> out;\n    vector<int> cur;\n    gen_partitions_rec(B, 1, distinctOnly, cur, out);\n    return out;\n}\n\nstatic string build_graph_string_partition(const vector<int>& parts, int type, int q) {\n    int B = 0;\n    for (int x : parts) B += x;\n    int N = B * q;\n\n    vector<int> block(N);\n    int ptr = 0, bid = 0;\n    for (int x : parts) {\n        int s = x * q;\n        for (int i = 0; i < s; i++) block[ptr++] = bid;\n        bid++;\n    }\n\n    string g;\n    g.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            bool same = (block[i] == block[j]);\n            bool e = (type == 0 ? same : !same);\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic vector<int> build_partition_deg_base(const vector<int>& parts, int type) {\n    int B = 0;\n    for (int x : parts) B += x;\n    vector<int> deg;\n    deg.reserve(B);\n    if (type == 0) {\n        for (int x : parts) {\n            for (int i = 0; i < x; i++) deg.push_back(x - 1);\n        }\n    } else {\n        for (int i = (int)parts.size() - 1; i >= 0; i--) {\n            int x = parts[i];\n            for (int t = 0; t < x; t++) deg.push_back(B - x);\n        }\n    }\n    return deg;\n}\n\nstatic vector<BaseCand> generate_partition_base_candidates(int B, bool distinctOnly) {\n    auto plist = generate_partitions(B, distinctOnly);\n    vector<BaseCand> res;\n    unordered_set<string> seen;\n\n    for (const auto& parts : plist) {\n        for (int type = 0; type <= 1; type++) {\n            string g = build_graph_string_partition(parts, type, 1);\n            if (!seen.insert(g).second) continue;\n            BaseCand c;\n            c.family = F_PARTITION;\n            c.B = B;\n            c.parts = parts;\n            c.type = type;\n            c.degBaseSorted = build_partition_deg_base(parts, type);\n            c.edgeBase = 0;\n            for (char ch : g) c.edgeBase += (ch == '1');\n            res.push_back(std::move(c));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const BaseCand& a, const BaseCand& b) {\n        if (a.edgeBase != b.edgeBase) return a.edgeBase < b.edgeBase;\n        if (a.type != b.type) return a.type < b.type;\n        return a.parts < b.parts;\n    });\n    return res;\n}\n\nstatic vector<BaseCand> generate_threshold_base_candidates(int B, int family) {\n    vector<BaseCand> res;\n    uint32_t lim = 1u << (B - 1);\n\n    for (uint32_t mask = 0; mask < lim; mask++) {\n        vector<int> suffix(B + 1, 0);\n        for (int i = B - 1; i >= 1; i--) {\n            suffix[i] = suffix[i + 1] + ((mask >> (i - 1)) & 1u);\n        }\n\n        vector<int> deg(B);\n        deg[0] = suffix[1];\n        int edges = 0;\n        for (int i = 1; i < B; i++) {\n            int bit = (mask >> (i - 1)) & 1u;\n            deg[i] = (bit ? i : 0) + suffix[i + 1];\n            edges += bit * i;\n        }\n        sort(deg.begin(), deg.end());\n\n        BaseCand c;\n        c.family = family;\n        c.B = B;\n        c.mask = mask;\n        c.degBaseSorted = std::move(deg);\n        c.edgeBase = edges;\n        res.push_back(std::move(c));\n    }\n\n    sort(res.begin(), res.end(), [](const BaseCand& a, const BaseCand& b) {\n        if (a.edgeBase != b.edgeBase) return a.edgeBase < b.edgeBase;\n        return a.mask < b.mask;\n    });\n    return res;\n}\n\nstatic long long dist2_degbase(const vector<int>& a, const vector<int>& b) {\n    long long s = 0;\n    for (int i = 0; i < (int)a.size(); i++) {\n        long long d = (long long)a[i] - b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstatic double selection_quality(const vector<BaseCand>& cands, const vector<int>& sel) {\n    if (sel.size() <= 1) return 0.0;\n    double sum = 0.0;\n    for (int i = 0; i < (int)sel.size(); i++) {\n        long long best = (1LL << 60);\n        for (int j = 0; j < (int)sel.size(); j++) if (i != j) {\n            best = min(best, dist2_degbase(cands[sel[i]].degBaseSorted, cands[sel[j]].degBaseSorted));\n        }\n        sum += (double)best;\n    }\n    return sum / sel.size();\n}\n\nstatic vector<BaseCand> select_codewords(const vector<BaseCand>& cands, int M) {\n    int C = (int)cands.size();\n    if (C <= M) return cands;\n\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int i, int j) {\n        if (cands[i].edgeBase != cands[j].edgeBase) return cands[i].edgeBase < cands[j].edgeBase;\n        return i < j;\n    });\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2], idx[C / 3], idx[(2 * C) / 3]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQual = -1.0;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<long long> minDist(C, (1LL << 60));\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                long long d = dist2_degbase(cands[x].degBaseSorted, cands[i].degBaseSorted);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        };\n\n        add_one(seed);\n        if (M >= 2) {\n            int far = -1;\n            long long best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                long long d = dist2_degbase(cands[seed].degBaseSorted, cands[i].degBaseSorted);\n                if (d > best) {\n                    best = d;\n                    far = i;\n                }\n            }\n            add_one(far);\n        }\n\n        while ((int)sel.size() < M) {\n            int nxt = -1;\n            long long best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double q = selection_quality(cands, sel);\n        if (q > bestQual) {\n            bestQual = q;\n            bestSel = sel;\n        }\n    }\n\n    vector<BaseCand> ret;\n    ret.reserve(M);\n    for (int id : bestSel) ret.push_back(cands[id]);\n    sort(ret.begin(), ret.end(), [](const BaseCand& a, const BaseCand& b) {\n        if (a.edgeBase != b.edgeBase) return a.edgeBase < b.edgeBase;\n        if (a.family != b.family) return a.family < b.family;\n        if (a.family == F_PARTITION) {\n            if (a.type != b.type) return a.type < b.type;\n            return a.parts < b.parts;\n        }\n        return a.mask < b.mask;\n    });\n    return ret;\n}\n\n// ------------------------------------------------------------\n// Family-specific builders for proxy search / full graphs\n// ------------------------------------------------------------\n\nstatic vector<double> build_proxy_expected_mu(const BaseCand& c, int q, double eps) {\n    int N = c.B * q;\n    double shift = eps * (N - 1);\n    double scale = 1.0 - 2.0 * eps;\n\n    vector<double> mu;\n    mu.reserve(N);\n\n    if (c.family == F_PARTITION) {\n        if (c.type == 0) {\n            for (int x : c.parts) {\n                int s = x * q;\n                double d = s - 1;\n                double m = shift + scale * d;\n                for (int i = 0; i < s; i++) mu.push_back(m);\n            }\n        } else {\n            for (int i = (int)c.parts.size() - 1; i >= 0; i--) {\n                int x = c.parts[i];\n                int s = x * q;\n                double d = N - s;\n                double m = shift + scale * d;\n                for (int i2 = 0; i2 < s; i2++) mu.push_back(m);\n            }\n        }\n    } else if (c.family == F_THRESHOLD_INDEP) {\n        for (int d0 : c.degBaseSorted) {\n            double d = 1.0 * q * d0;\n            double m = shift + scale * d;\n            for (int t = 0; t < q; t++) mu.push_back(m);\n        }\n    } else { // F_THRESHOLD_CLIQUE\n        for (int d0 : c.degBaseSorted) {\n            double d = 1.0 * q * d0 + (q - 1);\n            double m = shift + scale * d;\n            for (int t = 0; t < q; t++) mu.push_back(m);\n        }\n    }\n\n    return mu;\n}\n\nstatic inline bool threshold_base_edge(uint32_t mask, int u, int v) {\n    if (u == v) return false;\n    if (u > v) swap(u, v);\n    // In threshold construction, vertex v connects to all previous iff its bit is 1.\n    return ((mask >> (v - 1)) & 1u) != 0;\n}\n\nstatic string build_full_graph_string(const BaseCand& c, int q) {\n    int N = c.B * q;\n    string g;\n    g.reserve(N * (N - 1) / 2);\n\n    if (c.family == F_PARTITION) {\n        return build_graph_string_partition(c.parts, c.type, q);\n    }\n\n    // threshold families\n    bool cliqueInside = (c.family == F_THRESHOLD_CLIQUE);\n    for (int i = 0; i < N; i++) {\n        int bi = i / q;\n        for (int j = i + 1; j < N; j++) {\n            int bj = j / q;\n            bool e;\n            if (bi == bj) e = cliqueInside;\n            else e = threshold_base_edge(c.mask, bi, bj);\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\n// ------------------------------------------------------------\n// Generic codebook and decoder\n// ------------------------------------------------------------\n\nstruct Codebook {\n    int N = 0, M = 0;\n    double eps = 0.0;\n    double sigma2 = 0.0;\n    vector<string> graphStrs;\n    vector<vector<double>> mu;  // expected sorted degrees\n    vector<double> triMu, triVar;\n    double estScore = -1;\n};\n\nstatic Codebook build_codebook(const vector<BaseCand>& codes, int q, double eps) {\n    Codebook cb;\n    cb.M = (int)codes.size();\n    cb.N = codes[0].B * q;\n    cb.eps = eps;\n    cb.sigma2 = (cb.N - 1) * eps * (1.0 - eps);\n\n    cb.graphStrs.reserve(cb.M);\n    cb.mu.reserve(cb.M);\n    cb.triMu.reserve(cb.M);\n    cb.triVar.reserve(cb.M);\n\n    static unsigned char adj[MAXN][MAXN];\n\n    double shift = eps * (cb.N - 1);\n    double scale = 1.0 - 2.0 * eps;\n\n    for (const auto& c : codes) {\n        string g = build_full_graph_string(c, q);\n        cb.graphStrs.push_back(g);\n\n        int deg[MAXN] = {};\n        int pos = 0;\n        for (int i = 0; i < cb.N; i++) adj[i][i] = 0;\n        for (int i = 0; i < cb.N; i++) {\n            for (int j = i + 1; j < cb.N; j++) {\n                unsigned char bit = (unsigned char)(g[pos++] - '0');\n                adj[i][j] = adj[j][i] = bit;\n                if (bit) {\n                    deg[i]++;\n                    deg[j]++;\n                }\n            }\n        }\n\n        vector<int> sdeg(deg, deg + cb.N);\n        sort(sdeg.begin(), sdeg.end());\n\n        vector<double> mu(cb.N);\n        for (int i = 0; i < cb.N; i++) mu[i] = shift + scale * sdeg[i];\n        cb.mu.push_back(std::move(mu));\n\n        long long cnt[4] = {};\n        for (int i = 0; i < cb.N; i++) {\n            for (int j = i + 1; j < cb.N; j++) {\n                for (int k = j + 1; k < cb.N; k++) {\n                    int e = adj[i][j] + adj[i][k] + adj[j][k];\n                    cnt[e]++;\n                }\n            }\n        }\n\n        double a = 1.0 - eps, b = eps;\n        double triMean = 0.0;\n        triMean += cnt[3] * (a * a * a);\n        triMean += cnt[2] * (a * a * b);\n        triMean += cnt[1] * (a * b * b);\n        triMean += cnt[0] * (b * b * b);\n\n        double total = cnt[0] + cnt[1] + cnt[2] + cnt[3];\n        double p = (total > 0 ? triMean / total : 0.0);\n        double triVar = max(1.0, 4.0 * total * p * (1.0 - p)); // conservative\n\n        cb.triMu.push_back(triMean);\n        cb.triVar.push_back(triVar);\n    }\n\n    return cb;\n}\n\nstatic int count_triangles(const unsigned char adj[MAXN][MAXN], int N) {\n    int tri = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) if (adj[i][j]) {\n            for (int k = j + 1; k < N; k++) {\n                if (adj[i][k] && adj[j][k]) tri++;\n            }\n        }\n    }\n    return tri;\n}\n\nstatic int decode_codebook(const Codebook& cb, const unsigned char adj[MAXN][MAXN]) {\n    int N = cb.N, M = cb.M;\n\n    int deg[MAXN] = {};\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) if (adj[i][j]) {\n            deg[i]++;\n            deg[j]++;\n        }\n    }\n\n    vector<int> sortedDeg(deg, deg + N);\n    sort(sortedDeg.begin(), sortedDeg.end());\n\n    vector<pair<double,int>> sse;\n    sse.reserve(M);\n    for (int k = 0; k < M; k++) {\n        double cur = 0.0;\n        const auto& mu = cb.mu[k];\n        for (int i = 0; i < N; i++) {\n            double d = sortedDeg[i] - mu[i];\n            cur += d * d;\n        }\n        sse.push_back({cur, k});\n    }\n    sort(sse.begin(), sse.end());\n\n    if (cb.sigma2 < 1e-12) return sse[0].second;\n\n    const int K = min(M, 8);\n    double bestS = sse[0].first;\n    double delta = 2.0 * N * cb.sigma2 + 1.0; // \"close enough\" band\n\n    vector<pair<double,int>> close;\n    close.reserve(K);\n    for (int i = 0; i < K; i++) {\n        if (sse[i].first <= bestS + delta) close.push_back(sse[i]);\n    }\n    if ((int)close.size() <= 1) return sse[0].second;\n\n    int triObs = count_triangles(adj, N);\n\n    int ans = sse[0].second;\n    double bestScore = 1e100;\n    for (auto [ss, id] : close) {\n        double triZ = (triObs - cb.triMu[id]) * (triObs - cb.triMu[id]) / (cb.triVar[id] + 1.0);\n        double score = ss / (cb.sigma2 + 1e-9) + 0.25 * triZ;\n        if (score < bestScore) {\n            bestScore = score;\n            ans = id;\n        }\n    }\n    return ans;\n}\n\nstatic double estimate_actual_score(const Codebook& cb, int sampleS, int reps, uint64_t seed) {\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur(0.0, 1.0);\n    auto ids = sample_ids_evenly(cb.M, sampleS);\n\n    static unsigned char adj[MAXN][MAXN];\n    int err = 0, tot = 0;\n\n    for (int id : ids) {\n        const string& g = cb.graphStrs[id];\n        for (int rep = 0; rep < reps; rep++) {\n            int pos = 0;\n            for (int i = 0; i < cb.N; i++) adj[i][i] = 0;\n            for (int i = 0; i < cb.N; i++) {\n                for (int j = i + 1; j < cb.N; j++) {\n                    unsigned char bit = (unsigned char)(g[pos++] - '0');\n                    if (ur(rng) < cb.eps) bit ^= 1;\n                    adj[i][j] = adj[j][i] = bit;\n                }\n            }\n            // No shuffle needed in simulation: decoder uses permutation invariants.\n            int ans = decode_codebook(cb, adj);\n            if (ans != id) err++;\n            tot++;\n        }\n    }\n\n    return score_from_counts(err, tot, cb.N);\n}\n\n// ------------------------------------------------------------\n// Proxy search\n// ------------------------------------------------------------\n\nstatic vector<int> q_candidates(int qmax) {\n    set<int> s;\n    for (int q = 1; q <= min(qmax, 10); q++) s.insert(q);\n    for (int q = 12; q <= qmax; q += 2) s.insert(q);\n    s.insert(qmax);\n    return vector<int>(s.begin(), s.end());\n}\n\nstatic double estimate_proxy_score(const vector<BaseCand>& codes, int q, double eps, int reps) {\n    int M = (int)codes.size();\n    int N = codes[0].B * q;\n    double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n\n    vector<vector<double>> exps(M);\n    for (int i = 0; i < M; i++) exps[i] = build_proxy_expected_mu(codes[i], q, eps);\n\n    mt19937_64 rng(0x123456789ULL + 10007ULL * codes[0].B + 1000003ULL * q + 911382323ULL * codes[0].family);\n    normal_distribution<double> gauss(0.0, sigma);\n\n    vector<double> noisy(N);\n    int err = 0, tot = 0;\n\n    for (int rep = 0; rep < reps; rep++) {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < N; j++) {\n                double x = exps[i][j];\n                if (sigma > 0) x += gauss(rng);\n                x = max(0.0, min((double)(N - 1), x));\n                noisy[j] = x;\n            }\n            sort(noisy.begin(), noisy.end());\n\n            int bestId = 0;\n            double bestS = 1e100;\n            for (int t = 0; t < M; t++) {\n                double s = 0.0;\n                const auto& mu = exps[t];\n                for (int j = 0; j < N; j++) {\n                    double d = noisy[j] - mu[j];\n                    s += d * d;\n                    if (s >= bestS) break;\n                }\n                if (s < bestS) {\n                    bestS = s;\n                    bestId = t;\n                }\n            }\n            if (bestId != i) err++;\n            tot++;\n        }\n    }\n    return score_from_counts(err, tot, N);\n}\n\n// ------------------------------------------------------------\n// Main\n// ------------------------------------------------------------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    // --------------------------------------------------------\n    // Exact strategy for eps = 0\n    // --------------------------------------------------------\n    if (fabs(eps) < 1e-12) {\n        vector<int> Ns = {4, 5, 6};\n        SmallDB db;\n        int chosenN = -1;\n        for (int N : Ns) {\n            SmallDB cur = init_small_db(N);\n            if ((int)cur.reps.size() >= M) {\n                db = std::move(cur);\n                chosenN = N;\n                break;\n            }\n        }\n        if (chosenN == -1) {\n            db = init_small_db(6);\n            chosenN = 6;\n        }\n\n        vector<uint16_t> chosen(db.reps.begin(), db.reps.begin() + M);\n        unordered_map<int,int> repToIdx;\n        repToIdx.reserve(M * 2);\n        for (int i = 0; i < M; i++) repToIdx[(int)chosen[i]] = i;\n\n        cout << chosenN << '\\n';\n        for (int i = 0; i < M; i++) {\n            cout << small_mask_to_string(chosen[i], db.E) << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; q++) {\n            string H;\n            cin >> H;\n            uint16_t mask = 0;\n            for (int i = 0; i < db.E; i++) if (H[i] == '1') {\n                mask |= (uint16_t(1) << i);\n            }\n            uint16_t canon = canonicalize_small(db, mask);\n            int ans = repToIdx[(int)canon];\n            cout << ans << '\\n';\n            cout.flush();\n        }\n        return 0;\n    }\n\n    // --------------------------------------------------------\n    // Candidate strategy A: small exact graphs, only for very low noise\n    // --------------------------------------------------------\n    SmallStrategy bestSmall;\n    bool hasSmall = false;\n    if (eps <= 0.04) {\n        vector<int> smallNs;\n        if (M <= 11) smallNs = {4, 5, 6};\n        else if (M <= 34) smallNs = {5, 6};\n        else if (M <= 156) smallNs = {6};\n\n        for (int N : smallNs) {\n            SmallDB db = init_small_db(N);\n            if ((int)db.reps.size() < M) continue;\n\n            auto sel = select_small_code_indices(db, M);\n\n            SmallStrategy st;\n            st.N = N;\n            st.E = N * (N - 1) / 2;\n            st.M = M;\n            st.codeMasks.reserve(M);\n            st.codePermMasks.reserve(M);\n            st.graphStrs.reserve(M);\n\n            for (int id : sel) {\n                st.codeMasks.push_back(db.reps[id]);\n                st.codePermMasks.push_back(db.repPermMasks[id]);\n                st.graphStrs.push_back(small_mask_to_string(db.reps[id], st.E));\n            }\n\n            st.estScore = estimate_small_strategy(st, eps, 8, 0xABCDEF123456789ULL + 10007ULL * N + M);\n            if (!hasSmall || st.estScore > bestSmall.estScore) {\n                hasSmall = true;\n                bestSmall = std::move(st);\n            }\n        }\n    }\n\n    // --------------------------------------------------------\n    // Candidate strategy B: robust large families\n    // --------------------------------------------------------\n    struct Book {\n        int B;\n        string tag;\n        vector<BaseCand> codes;\n    };\n\n    vector<Book> books;\n\n    // Partition family: all partitions\n    {\n        vector<vector<BaseCand>> raw(24);\n        int Bmin = -1;\n        for (int B = 1; B <= 23; B++) {\n            raw[B] = generate_partition_base_candidates(B, false);\n            if (Bmin == -1 && (int)raw[B].size() >= M) Bmin = B;\n        }\n        if (Bmin == -1) Bmin = 23;\n        int Bhi = min(23, Bmin + 8);\n        for (int B = Bmin; B <= Bhi; B++) {\n            if ((int)raw[B].size() < M) continue;\n            books.push_back({B, \"part_all\", select_codewords(raw[B], M)});\n        }\n    }\n\n    // Partition family: distinct parts\n    {\n        vector<vector<BaseCand>> raw(24);\n        int Bmin = -1;\n        for (int B = 1; B <= 23; B++) {\n            raw[B] = generate_partition_base_candidates(B, true);\n            if (Bmin == -1 && (int)raw[B].size() >= M) Bmin = B;\n        }\n        if (Bmin != -1) {\n            int Bhi = min(23, Bmin + 6);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)raw[B].size() < M) continue;\n                books.push_back({B, \"part_distinct\", select_codewords(raw[B], M)});\n            }\n        }\n    }\n\n    // Threshold graph family: independent-set blow-up\n    {\n        int Bmin = 1;\n        while ((1 << max(0, Bmin - 1)) < M) Bmin++;\n        Bmin = max(Bmin, 4);\n        int Bhi = min(10, Bmin + 3);\n        for (int B = Bmin; B <= Bhi; B++) {\n            auto raw = generate_threshold_base_candidates(B, F_THRESHOLD_INDEP);\n            books.push_back({B, \"th_indep\", select_codewords(raw, M)});\n        }\n    }\n\n    // Threshold graph family: clique blow-up\n    {\n        int Bmin = 1;\n        while ((1 << max(0, Bmin - 1)) < M) Bmin++;\n        Bmin = max(Bmin, 4);\n        int Bhi = min(10, Bmin + 3);\n        for (int B = Bmin; B <= Bhi; B++) {\n            auto raw = generate_threshold_base_candidates(B, F_THRESHOLD_CLIQUE);\n            books.push_back({B, \"th_clique\", select_codewords(raw, M)});\n        }\n    }\n\n    struct Combo {\n        double proxy;\n        int bookIdx;\n        int q;\n    };\n    vector<Combo> combos;\n\n    for (int bi = 0; bi < (int)books.size(); bi++) {\n        int B = books[bi].B;\n        int qmax = 100 / B;\n        auto qs = q_candidates(qmax);\n\n        set<int> tried;\n        int localBestQ = 1;\n        double localBestProxy = -1.0;\n\n        auto try_q = [&](int q) {\n            if (q < 1 || q > qmax) return;\n            if (!tried.insert(q).second) return;\n            double pr = estimate_proxy_score(books[bi].codes, q, eps, 1);\n            combos.push_back({pr, bi, q});\n            if (pr > localBestProxy) {\n                localBestProxy = pr;\n                localBestQ = q;\n            }\n        };\n\n        for (int q : qs) try_q(q);\n        for (int q = localBestQ - 2; q <= localBestQ + 2; q++) try_q(q);\n    }\n\n    sort(combos.begin(), combos.end(), [](const Combo& a, const Combo& b) {\n        if (a.proxy != b.proxy) return a.proxy > b.proxy;\n        if (a.bookIdx != b.bookIdx) return a.bookIdx < b.bookIdx;\n        return a.q < b.q;\n    });\n\n    vector<Combo> uniq;\n    set<pair<int,int>> seenBQ;\n    for (auto c : combos) {\n        if (seenBQ.insert({c.bookIdx, c.q}).second) uniq.push_back(c);\n    }\n\n    Codebook bestCB;\n    double bestEst = -1.0;\n\n    int topCombos = min<int>(8, uniq.size());\n    for (int i = 0; i < topCombos; i++) {\n        const auto& c = uniq[i];\n        Codebook cb = build_codebook(books[c.bookIdx].codes, c.q, eps);\n        cb.estScore = estimate_actual_score(\n            cb,\n            min(M, 36),\n            2,\n            0x9E3779B97F4A7C15ULL + 10007ULL * books[c.bookIdx].B + c.q * 911ULL + i * 1000003ULL\n        );\n        if (cb.estScore > bestEst + 1e-15 || (abs(cb.estScore - bestEst) <= 1e-15 && cb.N < bestCB.N)) {\n            bestEst = cb.estScore;\n            bestCB = std::move(cb);\n        }\n    }\n\n    if (bestCB.N == 0) {\n        bestCB = build_codebook(books[0].codes, 1, eps);\n        bestEst = bestCB.estScore = estimate_actual_score(bestCB, min(M, 20), 1, 1234567);\n    }\n\n    // Compare against low-noise small strategy if available\n    bool useSmall = false;\n    if (hasSmall) {\n        if (bestSmall.estScore > bestEst) useSmall = true;\n    }\n\n    // --------------------------------------------------------\n    // Output chosen codebook\n    // --------------------------------------------------------\n    int N = useSmall ? bestSmall.N : bestCB.N;\n    cout << N << '\\n';\n    if (useSmall) {\n        for (int i = 0; i < M; i++) cout << bestSmall.graphStrs[i] << '\\n';\n    } else {\n        for (int i = 0; i < M; i++) cout << bestCB.graphStrs[i] << '\\n';\n    }\n    cout.flush();\n\n    // --------------------------------------------------------\n    // Query processing\n    // --------------------------------------------------------\n    if (useSmall) {\n        for (int q = 0; q < 100; q++) {\n            string H;\n            cin >> H;\n            uint16_t mask = 0;\n            for (int i = 0; i < bestSmall.E; i++) {\n                if (H[i] == '1') mask |= (uint16_t(1) << i);\n            }\n            int ans = decode_small(bestSmall, mask);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        static unsigned char adj[MAXN][MAXN];\n        for (int query = 0; query < 100; query++) {\n            string H;\n            cin >> H;\n            int pos = 0;\n            for (int i = 0; i < bestCB.N; i++) adj[i][i] = 0;\n            for (int i = 0; i < bestCB.N; i++) {\n                for (int j = i + 1; j < bestCB.N; j++) {\n                    unsigned char bit = (unsigned char)(H[pos++] - '0');\n                    adj[i][j] = adj[j][i] = bit;\n                }\n            }\n            int ans = decode_codebook(bestCB, adj);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x += 0x9e3779b97f4a7c15ull;\n        uint64_t z = x;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& a) {\n        for (int i = (int)a.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(a[i], a[j]);\n        }\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n    double mx, my;\n};\n\nstruct Adj {\n    int to, eid;\n};\n\nstruct PairW {\n    int a, b;\n    double w;\n};\n\nstruct State {\n    vector<int> day;       // size M\n    vector<int> cnt;       // size D\n    vector<double> load;   // normalized importance load per day\n    vector<double> same;   // size M*D, same[e*D+d] = conflict sum if e put on d\n};\n\nclass Solver {\n    static constexpr ll INF = (1LL << 60);\n    static constexpr ll UNREACH = 1000000000LL;\n    static constexpr double PI = 3.14159265358979323846;\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Adj>> g;\n    vector<pair<int,int>> pos;\n    vector<vector<int>> incident;\n    vector<int> degv;\n\n    double centroidX = 0.0, centroidY = 0.0;\n\n    vector<int> sources;\n    int S = 0;\n    vector<vector<ll>> baseDist; // S x N\n\n    vector<double> imp, impN;\n    vector<PairW> conflicts;\n    vector<vector<pair<int,double>>> neigh;\n    vector<double> neighSum;\n    double targetCnt = 0.0;\n    double targetLoad = 0.0;\n\n    chrono::steady_clock::time_point start_time;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    inline double& SAME(State& st, int e, int d) {\n        return st.same[(size_t)e * D + d];\n    }\n    inline double SAMEC(const State& st, int e, int d) const {\n        return st.same[(size_t)e * D + d];\n    }\n\n    void dijkstra_internal(int src, int banDay, const vector<int>& day,\n                           vector<ll>& dist,\n                           vector<int>* parentV = nullptr,\n                           vector<int>* parentE = nullptr) {\n        dist.assign(N, INF);\n        if (parentV) parentV->assign(N, -1);\n        if (parentE) parentE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n\n            for (const auto& a : g[v]) {\n                if (banDay >= 0 && day[a.eid] == banDay) continue;\n                int to = a.to;\n                ll nd = cd + edges[a.eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parentV) (*parentV)[to] = v;\n                    if (parentE) (*parentE)[to] = a.eid;\n                    pq.push({nd, to});\n                } else if (parentV && nd == dist[to]) {\n                    if ((*parentE)[to] == -1 || a.eid < (*parentE)[to]) {\n                        (*parentV)[to] = v;\n                        (*parentE)[to] = a.eid;\n                    }\n                }\n            }\n        }\n    }\n\n    void choose_sources() {\n        S = min(12, N);\n\n        // first source near centroid\n        int first = 0;\n        double best = 1e100;\n        for (int i = 0; i < N; ++i) {\n            double dx = pos[i].first - centroidX;\n            double dy = pos[i].second - centroidY;\n            double d2 = dx * dx + dy * dy;\n            if (d2 < best) {\n                best = d2;\n                first = i;\n            }\n        }\n\n        sources.clear();\n        vector<double> minD2(N, 1e100);\n\n        int cur = first;\n        for (int t = 0; t < S; ++t) {\n            sources.push_back(cur);\n            for (int i = 0; i < N; ++i) {\n                double dx = pos[i].first - pos[cur].first;\n                double dy = pos[i].second - pos[cur].second;\n                double d2 = dx * dx + dy * dy;\n                if (d2 < minD2[i]) minD2[i] = d2;\n            }\n            int nxt = -1;\n            double farv = -1.0;\n            for (int i = 0; i < N; ++i) {\n                bool used = false;\n                for (int s : sources) if (s == i) { used = true; break; }\n                if (used) continue;\n                if (minD2[i] > farv) {\n                    farv = minD2[i];\n                    nxt = i;\n                }\n            }\n            if (nxt == -1) break;\n            cur = nxt;\n        }\n        S = (int)sources.size();\n    }\n\n    void compute_importance() {\n        choose_sources();\n        baseDist.assign(S, vector<ll>(N));\n\n        double avgw = 0.0;\n        for (auto& e : edges) avgw += e.w;\n        avgw /= M;\n\n        vector<double> usage(M, 0.0);\n        vector<ll> dist;\n        vector<int> pv, pe;\n\n        vector<int> emptyDay; // banDay < 0 => ignored\n\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, -1, emptyDay, dist, &pv, &pe);\n            baseDist[si] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sub(N, 1);\n            for (int v : ord) {\n                if (v == src) continue;\n                if (pe[v] != -1) {\n                    usage[pe[v]] += sub[v];\n                    sub[pv[v]] += sub[v];\n                }\n            }\n        }\n\n        imp.assign(M, 1.0);\n        for (int e = 0; e < M; ++e) {\n            double wf = sqrt((double)edges[e].w / avgw);\n            imp[e] = sqrt(1.0 + usage[e]) * (0.7 + 0.3 * wf);\n        }\n\n        double avgImp = 0.0;\n        for (double x : imp) avgImp += x;\n        avgImp /= M;\n\n        impN.resize(M);\n        for (int e = 0; e < M; ++e) impN[e] = imp[e] / avgImp;\n\n        targetCnt = (double)M / D;\n        double sumImpN = 0.0;\n        for (double x : impN) sumImpN += x;\n        targetLoad = sumImpN / D;\n    }\n\n    void build_conflicts() {\n        struct Tmp {\n            int a, b;\n            double w;\n        };\n        vector<Tmp> tmp;\n        tmp.reserve(200000);\n\n        // strong conflicts for edges sharing a vertex\n        for (int v = 0; v < N; ++v) {\n            auto& inc = incident[v];\n            int deg = (int)inc.size();\n            double lowFactor = 1.0 + 0.8 * max(0, 5 - deg); // deg2 -> strong\n            for (int i = 0; i < deg; ++i) {\n                for (int j = i + 1; j < deg; ++j) {\n                    int a = inc[i], b = inc[j];\n                    if (a > b) swap(a, b);\n                    double w = 40.0 * lowFactor * (0.7 + 0.15 * (impN[a] + impN[b]));\n                    tmp.push_back({a, b, w});\n                }\n            }\n        }\n\n        // medium conflicts for spatially close edges\n        const double R = 110.0;\n        const double R2 = R * R;\n        const int CELL = 110;\n        const int G = 1000 / CELL + 4;\n\n        auto cell_id = [&](int x, int y) {\n            return x * G + y;\n        };\n\n        vector<vector<int>> cells(G * G);\n        for (int e = 0; e < M; ++e) {\n            int cx = min(G - 1, max(0, (int)(edges[e].mx / CELL)));\n            int cy = min(G - 1, max(0, (int)(edges[e].my / CELL)));\n            cells[cell_id(cx, cy)].push_back(e);\n        }\n\n        auto share_vertex = [&](int a, int b) -> bool {\n            const auto& A = edges[a];\n            const auto& B = edges[b];\n            return A.u == B.u || A.u == B.v || A.v == B.u || A.v == B.v;\n        };\n\n        for (int x = 0; x < G; ++x) {\n            for (int y = 0; y < G; ++y) {\n                int id1 = cell_id(x, y);\n                for (int nx = max(0, x - 1); nx <= min(G - 1, x + 1); ++nx) {\n                    for (int ny = max(0, y - 1); ny <= min(G - 1, y + 1); ++ny) {\n                        if (nx < x || (nx == x && ny < y)) continue;\n                        int id2 = cell_id(nx, ny);\n                        const auto& c1 = cells[id1];\n                        const auto& c2 = cells[id2];\n                        if (id1 == id2) {\n                            for (int i = 0; i < (int)c1.size(); ++i) {\n                                for (int j = i + 1; j < (int)c1.size(); ++j) {\n                                    int a = c1[i], b = c1[j];\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        if (a > b) swap(a, b);\n                                        tmp.push_back({a, b, w});\n                                    }\n                                }\n                            }\n                        } else {\n                            for (int a : c1) {\n                                for (int b : c2) {\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        int x1 = a, x2 = b;\n                                        if (x1 > x2) swap(x1, x2);\n                                        tmp.push_back({x1, x2, w});\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        sort(tmp.begin(), tmp.end(), [&](const Tmp& p, const Tmp& q) {\n            if (p.a != q.a) return p.a < q.a;\n            return p.b < q.b;\n        });\n\n        conflicts.clear();\n        for (int i = 0; i < (int)tmp.size(); ) {\n            int j = i + 1;\n            double sw = tmp[i].w;\n            while (j < (int)tmp.size() && tmp[j].a == tmp[i].a && tmp[j].b == tmp[i].b) {\n                sw += tmp[j].w;\n                ++j;\n            }\n            conflicts.push_back({tmp[i].a, tmp[i].b, sw});\n            i = j;\n        }\n\n        neigh.assign(M, {});\n        neighSum.assign(M, 0.0);\n        for (auto& p : conflicts) {\n            neigh[p.a].push_back({p.b, p.w});\n            neigh[p.b].push_back({p.a, p.w});\n            neighSum[p.a] += p.w;\n            neighSum[p.b] += p.w;\n        }\n    }\n\n    inline double add_cost(int cnt, double load, double ie, double lc, double li) const {\n        double dc = (cnt + 1 - targetCnt) * (cnt + 1 - targetCnt) - (cnt - targetCnt) * (cnt - targetCnt);\n        double dl = (load + ie - targetLoad) * (load + ie - targetLoad) - (load - targetLoad) * (load - targetLoad);\n        return lc * dc + li * dl;\n    }\n\n    inline double move_delta_proxy(const State& st, int e, int b, double lc, double li) const {\n        int a = st.day[e];\n        if (a == b) return 0.0;\n        if (st.cnt[b] >= K) return 1e100;\n\n        double pairDelta = SAMEC(st, e, b) - SAMEC(st, e, a);\n\n        double dc =\n            (st.cnt[a] - 1 - targetCnt) * (st.cnt[a] - 1 - targetCnt) +\n            (st.cnt[b] + 1 - targetCnt) * (st.cnt[b] + 1 - targetCnt) -\n            (st.cnt[a] - targetCnt) * (st.cnt[a] - targetCnt) -\n            (st.cnt[b] - targetCnt) * (st.cnt[b] - targetCnt);\n\n        double ie = impN[e];\n        double dl =\n            (st.load[a] - ie - targetLoad) * (st.load[a] - ie - targetLoad) +\n            (st.load[b] + ie - targetLoad) * (st.load[b] + ie - targetLoad) -\n            (st.load[a] - targetLoad) * (st.load[a] - targetLoad) -\n            (st.load[b] - targetLoad) * (st.load[b] - targetLoad);\n\n        return pairDelta + lc * dc + li * dl;\n    }\n\n    void apply_move(State& st, int e, int b) {\n        int a = st.day[e];\n        if (a == b) return;\n        st.cnt[a]--;\n        st.cnt[b]++;\n        st.load[a] -= impN[e];\n        st.load[b] += impN[e];\n\n        for (auto [f, w] : neigh[e]) {\n            SAME(st, f, a) -= w;\n            SAME(st, f, b) += w;\n        }\n        st.day[e] = b;\n    }\n\n    State build_state(const vector<int>& day) {\n        State st;\n        st.day = day;\n        st.cnt.assign(D, 0);\n        st.load.assign(D, 0.0);\n\n        for (int e = 0; e < M; ++e) {\n            st.cnt[day[e]]++;\n            st.load[day[e]] += impN[e];\n        }\n\n        st.same.assign((size_t)M * D, 0.0);\n        for (auto& p : conflicts) {\n            SAME(st, p.a, st.day[p.b]) += p.w;\n            SAME(st, p.b, st.day[p.a]) += p.w;\n        }\n        return st;\n    }\n\n    vector<int> construct_initial(int type, RNG& rng, double lc, double li) {\n        vector<int> order;\n        order.reserve(M);\n        vector<int> pref(M, -1);\n\n        if (type == 0) {\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = neighSum[e] + 5.0 * impN[e] + 3.0 * rng.next_double();\n                arr.push_back({-key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n        } else if (type == 1) {\n            double th = rng.next_double() * 2.0 * PI;\n            double cs = cos(th), sn = sin(th);\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = edges[e].mx * cs + edges[e].my * sn + 1e-6 * rng.next_double();\n                arr.push_back({key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        } else {\n            double shift = rng.next_double() * 2.0 * PI;\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double ang = atan2(edges[e].my - centroidY, edges[e].mx - centroidX) - shift;\n                while (ang < 0) ang += 2.0 * PI;\n                while (ang >= 2.0 * PI) ang -= 2.0 * PI;\n                arr.push_back({ang + 1e-6 * rng.next_double(), e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        }\n\n        double prefPenalty = 8.0 + 6.0 * rng.next_double();\n\n        vector<int> day(M, -1);\n        vector<int> cnt(D, 0);\n        vector<double> load(D, 0.0);\n        array<double, 32> tmpConf{};\n\n        for (int e : order) {\n            for (int d = 0; d < D; ++d) tmpConf[d] = 0.0;\n            for (auto [f, w] : neigh[e]) {\n                int df = day[f];\n                if (df != -1) tmpConf[df] += w;\n            }\n\n            int bestd = -1;\n            double bestScore = 1e100;\n            int offset = rng.next_int(D);\n\n            for (int zz = 0; zz < D; ++zz) {\n                int d = (offset + zz) % D;\n                if (cnt[d] >= K) continue;\n                double sc = tmpConf[d] + add_cost(cnt[d], load[d], impN[e], lc, li);\n                if (pref[e] != -1 && d != pref[e]) sc += prefPenalty;\n                sc += 1e-7 * rng.next_double();\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestd = d;\n                }\n            }\n\n            if (bestd == -1) {\n                // fallback, should not happen\n                bestd = 0;\n                while (cnt[bestd] >= K) ++bestd;\n            }\n\n            day[e] = bestd;\n            cnt[bestd]++;\n            load[bestd] += impN[e];\n        }\n\n        return day;\n    }\n\n    void proxy_improve(State& st, RNG& rng, double lc, double li) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < 8; ++pass) {\n            rng.shuffle_vec(ord);\n            int moved = 0;\n\n            for (int e : ord) {\n                int a = st.day[e];\n                int bestd = a;\n                double bestDelta = -1e-9;\n\n                int offset = rng.next_int(D);\n                for (int zz = 0; zz < D; ++zz) {\n                    int d = (offset + zz) % D;\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                    }\n                }\n\n                if (bestd != a) {\n                    apply_move(st, e, bestd);\n                    moved++;\n                }\n            }\n\n            if (moved == 0) break;\n            if (elapsed() > 4.5) break;\n        }\n    }\n\n    ll eval_day_cost(int banDay, const vector<int>& day) {\n        ll res = 0;\n        vector<ll> dist;\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, banDay, day, dist, nullptr, nullptr);\n            const auto& bd = baseDist[si];\n            for (int v = 0; v < N; ++v) {\n                if (v == src) continue;\n                ll nd = (dist[v] >= INF / 2 ? UNREACH : dist[v]);\n                res += nd - bd[v];\n            }\n        }\n        return res;\n    }\n\n    ll eval_schedule(const vector<int>& day, const vector<int>& cnt, vector<ll>& dayCost) {\n        dayCost.assign(D, 0);\n        ll total = 0;\n        for (int d = 0; d < D; ++d) {\n            if (cnt[d] == 0) continue;\n            dayCost[d] = eval_day_cost(d, day);\n            total += dayCost[d];\n        }\n        return total;\n    }\n\n    void actual_refine(vector<int>& bestDay, double lc, double li) {\n        State st = build_state(bestDay);\n        vector<ll> dayCost;\n        ll curScore = eval_schedule(st.day, st.cnt, dayCost);\n\n        int accepted = 0;\n        while (elapsed() < 5.45 && accepted < 25) {\n            vector<int> worstOrd(D);\n            iota(worstOrd.begin(), worstOrd.end(), 0);\n            sort(worstOrd.begin(), worstOrd.end(), [&](int a, int b) {\n                return dayCost[a] > dayCost[b];\n            });\n\n            int takeDays = min(3, D);\n            array<int, 32> isTop{};\n            for (int i = 0; i < takeDays; ++i) isTop[worstOrd[i]] = 1;\n\n            vector<pair<double,int>> candEdges;\n            candEdges.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                int d = st.day[e];\n                if (!isTop[d]) continue;\n                double score = SAMEC(st, e, d) + 4.0 * impN[e];\n                candEdges.push_back({-score, e});\n            }\n\n            if (candEdges.empty()) break;\n            sort(candEdges.begin(), candEdges.end());\n            if ((int)candEdges.size() > 50) candEdges.resize(50);\n\n            vector<int> lowOrd(D);\n            iota(lowOrd.begin(), lowOrd.end(), 0);\n            sort(lowOrd.begin(), lowOrd.end(), [&](int a, int b) {\n                return dayCost[a] < dayCost[b];\n            });\n\n            bool moved = false;\n\n            for (auto [negScore, e] : candEdges) {\n                if (elapsed() > 5.45) break;\n\n                int a = st.day[e];\n                vector<pair<double,int>> pd;\n                pd.reserve(D);\n\n                for (int d = 0; d < D; ++d) {\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    pd.push_back({delta, d});\n                }\n                if (pd.empty()) continue;\n\n                sort(pd.begin(), pd.end());\n                vector<int> candDays;\n                for (int i = 0; i < (int)pd.size() && i < 4; ++i) candDays.push_back(pd[i].second);\n                for (int i = 0; i < min(2, D); ++i) {\n                    int d = lowOrd[i];\n                    if (d == a || st.cnt[d] >= K) continue;\n                    bool found = false;\n                    for (int x : candDays) if (x == d) found = true;\n                    if (!found) candDays.push_back(d);\n                }\n\n                ll bestDelta = 0;\n                int bestd = -1;\n                ll bestA = 0, bestB = 0;\n\n                int old = st.day[e];\n                for (int d : candDays) {\n                    st.day[e] = d;\n                    ll na = eval_day_cost(a, st.day);\n                    ll nb = eval_day_cost(d, st.day);\n                    ll delta = (na + nb) - (dayCost[a] + dayCost[d]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                        bestA = na;\n                        bestB = nb;\n                    }\n                }\n                st.day[e] = old;\n\n                if (bestd != -1) {\n                    apply_move(st, e, bestd);\n                    dayCost[a] = bestA;\n                    dayCost[bestd] = bestB;\n                    curScore += bestDelta;\n                    accepted++;\n                    moved = true;\n                    break;\n                }\n            }\n\n            if (!moved) break;\n        }\n\n        bestDay = st.day;\n        (void)curScore;\n    }\n\npublic:\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(N, {});\n        degv.assign(N, 0);\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            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            degv[u]++;\n            degv[v]++;\n        }\n\n        pos.resize(N);\n        for (int i = 0; i < N; ++i) {\n            cin >> pos[i].first >> pos[i].second;\n            centroidX += pos[i].first;\n            centroidY += pos[i].second;\n        }\n        centroidX /= N;\n        centroidY /= N;\n\n        for (int i = 0; i < M; ++i) {\n            edges[i].mx = 0.5 * (pos[edges[i].u].first + pos[edges[i].v].first);\n            edges[i].my = 0.5 * (pos[edges[i].u].second + pos[edges[i].v].second);\n        }\n\n        compute_importance();\n        build_conflicts();\n\n        uint64_t seedBase = 1469598103934665603ull;\n        seedBase ^= (uint64_t)N + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)M + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)D + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)K + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n\n        vector<int> bestDay;\n        ll bestScore = (1LL << 62);\n        double bestLc = 4.5, bestLi = 2.0;\n\n        int runs = 0;\n        while (elapsed() < 3.8 && runs < 12) {\n            RNG rng(seedBase + 1000003ull * (uint64_t)runs + 1234567ull);\n\n            double lc = 3.5 + 2.5 * rng.next_double();\n            double li = 1.5 + 2.0 * rng.next_double();\n\n            int type = runs % 3;\n            vector<int> initDay = construct_initial(type, rng, lc, li);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, lc, li);\n\n            vector<ll> dayCost;\n            ll sc = eval_schedule(st.day, st.cnt, dayCost);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestDay = st.day;\n                bestLc = lc;\n                bestLi = li;\n            }\n            runs++;\n        }\n\n        if (bestDay.empty()) {\n            RNG rng(seedBase);\n            vector<int> initDay = construct_initial(0, rng, 4.5, 2.0);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, 4.5, 2.0);\n            bestDay = st.day;\n        }\n\n        actual_refine(bestDay, bestLc, bestLi);\n\n        for (int i = 0; i < M; ++i) {\n            if (i) cout << ' ';\n            cout << bestDay[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\nstatic constexpr int MAXD = 14;\nstatic constexpr int MAXN = MAXD * MAXD * MAXD;\nstatic constexpr int NEG_INF = -1000000000;\n\nint D, Ncells;\n\nstring fstr[2][MAXD], rstr[2][MAXD];\nuint16_t actXMask[2][MAXD], actYMask[2][MAXD];\nvector<int> actXList[2][MAXD], actYList[2][MAXD];\nuint8_t activeCell[2][MAXD][MAXD][MAXD];\n\nchrono::steady_clock::time_point g_start;\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\ninline void decode3(int id, int &x, int &y, int &z) {\n    x = id / (D * D);\n    int rem = id % (D * D);\n    y = rem / D;\n    z = rem % D;\n}\ninline int popcnt16(uint16_t x) {\n    return __builtin_popcount((unsigned)x);\n}\n\nuint32_t tiny_hash(uint32_t x) {\n    x ^= x >> 16;\n    x *= 0x7feb352dU;\n    x ^= x >> 15;\n    x *= 0x846ca68bU;\n    x ^= x >> 16;\n    return x;\n}\ninline int tiny_noise(int seed, int x, int y, int z) {\n    uint32_t v = (uint32_t)seed * 1000003u\n               ^ (uint32_t)(x + 1) * 911382323u\n               ^ (uint32_t)(y + 1) * 972663749u\n               ^ (uint32_t)(z + 1) * 19260817u;\n    return (int)(tiny_hash(v) & 31u);\n}\n\nstruct Comp {\n    vector<int> cells;\n    int vol = 0;\n};\n\nstruct ShapeComp {\n    vector<int> cells;\n    int vol = 0;\n    string sig;\n};\n\nstruct LineSeg {\n    int axis; // 0:x, 1:y, 2:z\n    int x, y, z;\n    int len;\n};\n\nstruct LineSegCmp {\n    bool operator()(const LineSeg& a, const LineSeg& b) const {\n        if (a.len != b.len) return a.len < b.len;\n        if (a.axis != b.axis) return a.axis > b.axis;\n        if (a.x != b.x) return a.x > b.x;\n        if (a.y != b.y) return a.y > b.y;\n        return a.z > b.z;\n    }\n};\n\nstruct Candidate {\n    array<uint8_t, MAXN> occ{};\n    vector<ShapeComp> comps;\n};\n\nstruct CoreInfo {\n    vector<char> keep;\n    long double scoreCore = 0.0L;\n    uint16_t covX[MAXD]{};\n    uint16_t covY[MAXD]{};\n    uint16_t coreRow[MAXD][MAXD]{}; // bitmask of y for each (z,x)\n    int remVol[2]{};\n};\n\nstruct Param {\n    int dir;   // +1 forward, -1 backward\n    int alpha; // continuation reward\n    int beta;  // future run reward\n    int seed;  // tie-break diversity\n};\n\nstruct PairPlan {\n    long double extraScore = 0.0L;\n    vector<pair<int,int>> matchedExtra; // exact-shape matched extra components\n    int axis1 = 2, axis2 = 2;\n};\n\nstruct EvalResult {\n    bool ok = false;\n    long double score = 1e100L;\n    Candidate c1, c2;\n    PairPlan plan;\n};\n\nvector<Comp> commonComps;\nvector<array<int,3>> rotPerm;\nvector<array<int,3>> rotSign;\n\nint runF[2][MAXD][MAXD][MAXD + 1];\nint runB[2][MAXD][MAXD][MAXD];\n\nint perm_parity(const array<int,3>& p) {\n    int inv = 0;\n    for (int i = 0; i < 3; i++) for (int j = i + 1; j < 3; j++) {\n        if (p[i] > p[j]) inv++;\n    }\n    return (inv % 2 == 0 ? 1 : -1);\n}\n\nvoid init_rotations() {\n    rotPerm.clear();\n    rotSign.clear();\n    array<int,3> p = {0,1,2};\n    sort(p.begin(), p.end());\n    do {\n        int par = perm_parity(p);\n        for (int sx : {-1, 1}) for (int sy : {-1, 1}) for (int sz : {-1, 1}) {\n            if (par * sx * sy * sz == 1) {\n                rotPerm.push_back(p);\n                rotSign.push_back({sx, sy, sz});\n            }\n        }\n    } while (next_permutation(p.begin(), p.end()));\n}\n\nstring canonical_signature(const vector<int>& cells) {\n    vector<array<int,3>> coords;\n    coords.reserve(cells.size());\n    for (int id : cells) {\n        int x, y, z;\n        decode3(id, x, y, z);\n        coords.push_back({x, y, z});\n    }\n\n    string best;\n    bool first = true;\n\n    for (int r = 0; r < (int)rotPerm.size(); r++) {\n        vector<array<int,3>> t;\n        t.reserve(coords.size());\n        int mn0 = INT_MAX, mn1 = INT_MAX, mn2 = INT_MAX;\n\n        const auto& p = rotPerm[r];\n        const auto& s = rotSign[r];\n\n        for (auto &c : coords) {\n            int v[3] = {c[0], c[1], c[2]};\n            int a = s[0] * v[p[0]];\n            int b = s[1] * v[p[1]];\n            int cc = s[2] * v[p[2]];\n            mn0 = min(mn0, a);\n            mn1 = min(mn1, b);\n            mn2 = min(mn2, cc);\n            t.push_back({a, b, cc});\n        }\n\n        for (auto &q : t) {\n            q[0] -= mn0;\n            q[1] -= mn1;\n            q[2] -= mn2;\n        }\n        sort(t.begin(), t.end());\n\n        string sig;\n        sig.reserve(t.size() * 3);\n        for (auto &q : t) {\n            sig.push_back((char)q[0]);\n            sig.push_back((char)q[1]);\n            sig.push_back((char)q[2]);\n        }\n        if (first || sig < best) {\n            best = std::move(sig);\n            first = false;\n        }\n    }\n    return best;\n}\n\nvoid extract_shape_components(const array<uint8_t, MAXN>& occ, vector<ShapeComp>& out) {\n    out.clear();\n    vector<uint8_t> vis(Ncells, 0);\n    const int dx[6] = {1, -1, 0, 0, 0, 0};\n    const int dy[6] = {0, 0, 1, -1, 0, 0};\n    const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    for (int s = 0; s < Ncells; s++) {\n        if (!occ[s] || vis[s]) continue;\n        queue<int> q;\n        q.push(s);\n        vis[s] = 1;\n        ShapeComp c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (occ[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        c.sig = canonical_signature(c.cells);\n        out.push_back(std::move(c));\n    }\n}\n\nvoid build_full_common_components() {\n    vector<uint8_t> common(Ncells, 0);\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (activeCell[0][x][y][z] && activeCell[1][x][y][z]) {\n            common[idx3(x, y, z)] = 1;\n        }\n    }\n\n    vector<uint8_t> vis(Ncells, 0);\n    const int dx[6] = {1, -1, 0, 0, 0, 0};\n    const int dy[6] = {0, 0, 1, -1, 0, 0};\n    const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    for (int s = 0; s < Ncells; s++) {\n        if (!common[s] || vis[s]) continue;\n        queue<int> q;\n        q.push(s);\n        vis[s] = 1;\n        Comp c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (common[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        commonComps.push_back(std::move(c));\n    }\n}\n\nCoreInfo build_core_from_keep(const vector<char>& keep) {\n    CoreInfo core;\n    core.keep = keep;\n    for (int z = 0; z < D; z++) {\n        core.covX[z] = 0;\n        core.covY[z] = 0;\n        for (int x = 0; x < D; x++) core.coreRow[z][x] = 0;\n    }\n\n    for (int cid = 0; cid < (int)commonComps.size(); cid++) {\n        if (!keep[cid]) continue;\n        core.scoreCore += 1.0L / (long double)commonComps[cid].vol;\n        for (int id : commonComps[cid].cells) {\n            int x, y, z;\n            decode3(id, x, y, z);\n            core.covX[z] |= (uint16_t(1) << x);\n            core.covY[z] |= (uint16_t(1) << y);\n            core.coreRow[z][x] |= (uint16_t(1) << y);\n        }\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        int vol = 0;\n        for (int z = 0; z < D; z++) {\n            int ur = popcnt16(actXMask[obj][z] & ~core.covX[z]);\n            int uc = popcnt16(actYMask[obj][z] & ~core.covY[z]);\n            vol += max(ur, uc);\n        }\n        core.remVol[obj] = vol;\n    }\n    return core;\n}\n\nCoreInfo build_core_by_threshold(int threshold) {\n    vector<char> keep(commonComps.size(), 0);\n    for (int i = 0; i < (int)commonComps.size(); i++) {\n        if (commonComps[i].vol > threshold) keep[i] = 1;\n    }\n    return build_core_from_keep(keep);\n}\n\nvoid build_runs(const CoreInfo& core) {\n    for (int obj = 0; obj < 2; obj++) {\n        for (int x = 0; x < D; x++) {\n            for (int y = 0; y < D; y++) {\n                runF[obj][x][y][D] = 0;\n                for (int z = D - 1; z >= 0; z--) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runF[obj][x][y][z] = avail ? 1 + runF[obj][x][y][z + 1] : 0;\n                }\n                for (int z = 0; z < D; z++) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runB[obj][x][y][z] = avail ? 1 + (z ? runB[obj][x][y][z - 1] : 0) : 0;\n                }\n            }\n        }\n    }\n}\n\n// domain items choose one among `choices`, every `mandatory` value must be used at least once\nvector<int> solve_dp_assignment(\n    const vector<int>& domain,\n    const vector<int>& choices,\n    const vector<int>& mandatory,\n    int w[MAXD][MAXD]\n) {\n    int p = (int)domain.size();\n    int q = (int)choices.size();\n    int m = (int)mandatory.size();\n\n    vector<int> ret(p, 0);\n    if (p == 0) return ret;\n\n    int pos[MAXD];\n    for (int i = 0; i < MAXD; i++) pos[i] = -1;\n    for (int i = 0; i < m; i++) pos[mandatory[i]] = i;\n\n    int bitOfChoice[MAXD];\n    for (int j = 0; j < q; j++) {\n        bitOfChoice[j] = (pos[choices[j]] == -1 ? 0 : (1 << pos[choices[j]]));\n    }\n\n    int S = 1 << m;\n    static int dp[1 << MAXD], ndp[1 << MAXD];\n    static uint16_t parentMask[MAXD + 1][1 << MAXD];\n    static int8_t parentChoice[MAXD + 1][1 << MAXD];\n\n    for (int mask = 0; mask < S; mask++) dp[mask] = NEG_INF;\n    dp[0] = 0;\n\n    for (int i = 0; i < p; i++) {\n        for (int mask = 0; mask < S; mask++) ndp[mask] = NEG_INF;\n        for (int mask = 0; mask < S; mask++) if (dp[mask] > NEG_INF / 2) {\n            for (int j = 0; j < q; j++) {\n                int ww = w[i][j];\n                if (ww <= NEG_INF / 2) continue;\n                int nmask = mask | bitOfChoice[j];\n                int val = dp[mask] + ww;\n                if (val > ndp[nmask]) {\n                    ndp[nmask] = val;\n                    parentMask[i + 1][nmask] = (uint16_t)mask;\n                    parentChoice[i + 1][nmask] = (int8_t)j;\n                }\n            }\n        }\n        for (int mask = 0; mask < S; mask++) dp[mask] = ndp[mask];\n    }\n\n    int full = S - 1;\n    if (dp[full] <= NEG_INF / 2) {\n        for (int i = 0; i < p; i++) {\n            int bestj = 0, bestv = NEG_INF;\n            for (int j = 0; j < q; j++) {\n                if (w[i][j] > bestv) {\n                    bestv = w[i][j];\n                    bestj = j;\n                }\n            }\n            ret[i] = bestj;\n        }\n        return ret;\n    }\n\n    int mask = full;\n    for (int i = p; i >= 1; i--) {\n        int j = parentChoice[i][mask];\n        ret[i - 1] = j;\n        mask = parentMask[i][mask];\n    }\n    return ret;\n}\n\nCandidate build_candidate_dp(int obj, const CoreInfo& core, const Param& prm) {\n    Candidate cand;\n    cand.occ.fill(0);\n\n    uint16_t prevRow[MAXD]{};\n    uint16_t curRow[MAXD]{};\n\n    int zStart = (prm.dir == 1 ? 0 : D - 1);\n    int zEnd   = (prm.dir == 1 ? D : -1);\n    int zStep  = (prm.dir == 1 ? 1 : -1);\n\n    for (int z = zStart; z != zEnd; z += zStep) {\n        for (int x = 0; x < D; x++) curRow[x] = 0;\n\n        vector<int> uncRows, uncCols;\n        uint16_t rowMask = actXMask[obj][z] & ~core.covX[z];\n        uint16_t colMask = actYMask[obj][z] & ~core.covY[z];\n\n        for (int x : actXList[obj][z]) if ((rowMask >> x) & 1) uncRows.push_back(x);\n        for (int y : actYList[obj][z]) if ((colMask >> y) & 1) uncCols.push_back(y);\n\n        if (uncRows.empty() && uncCols.empty()) {\n            memcpy(prevRow, curRow, sizeof(prevRow));\n            continue;\n        }\n\n        int w[MAXD][MAXD];\n        for (int i = 0; i < MAXD; i++) for (int j = 0; j < MAXD; j++) w[i][j] = NEG_INF;\n\n        if ((int)uncRows.size() >= (int)uncCols.size()) {\n            const auto& domain = uncRows;\n            const auto& choices = actYList[obj][z];\n            const auto& mandatory = uncCols;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int y = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue;\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                int y = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        } else {\n            const auto& domain = uncCols;\n            const auto& choices = actXList[obj][z];\n            const auto& mandatory = uncRows;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int x = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue;\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                int x = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        }\n\n        memcpy(prevRow, curRow, sizeof(prevRow));\n    }\n\n    extract_shape_components(cand.occ, cand.comps);\n    return cand;\n}\n\nCandidate build_candidate_group(int obj, const CoreInfo& core, int pattern) {\n    Candidate cand;\n    cand.occ.fill(0);\n\n    for (int z = 0; z < D; z++) {\n        vector<int> uncRows, uncCols;\n        uint16_t rowMask = actXMask[obj][z] & ~core.covX[z];\n        uint16_t colMask = actYMask[obj][z] & ~core.covY[z];\n\n        for (int x : actXList[obj][z]) if ((rowMask >> x) & 1) uncRows.push_back(x);\n        for (int y : actYList[obj][z]) if ((colMask >> y) & 1) uncCols.push_back(y);\n\n        if (uncRows.empty() && uncCols.empty()) continue;\n\n        if ((int)uncRows.size() >= (int)uncCols.size()) {\n            vector<int> X = uncRows;\n            vector<int> Yreq = uncCols;\n            const auto& Yall = actYList[obj][z];\n\n            if (pattern & 2) reverse(X.begin(), X.end());\n            if (pattern & 1) reverse(Yreq.begin(), Yreq.end());\n\n            if (Yreq.empty()) {\n                int sel = 0;\n                if ((int)Yall.size() == 1) sel = 0;\n                else if (pattern == 0) sel = 0;\n                else if (pattern == 1) sel = (int)Yall.size() - 1;\n                else if (pattern == 2) sel = (int)Yall.size() / 2;\n                else sel = ((int)Yall.size() - 1) / 2;\n                int y = Yall[sel];\n                for (int x : X) cand.occ[idx3(x, y, z)] = 1;\n            } else {\n                int p = (int)X.size(), k = (int)Yreq.size();\n                for (int g = 0; g < k; g++) {\n                    int l = (long long)g * p / k;\n                    int r = (long long)(g + 1) * p / k;\n                    int y = Yreq[g];\n                    for (int i = l; i < r; i++) {\n                        cand.occ[idx3(X[i], y, z)] = 1;\n                    }\n                }\n            }\n        } else {\n            vector<int> Y = uncCols;\n            vector<int> Xreq = uncRows;\n            const auto& Xall = actXList[obj][z];\n\n            if (pattern & 2) reverse(Y.begin(), Y.end());\n            if (pattern & 1) reverse(Xreq.begin(), Xreq.end());\n\n            if (Xreq.empty()) {\n                int sel = 0;\n                if ((int)Xall.size() == 1) sel = 0;\n                else if (pattern == 0) sel = 0;\n                else if (pattern == 1) sel = (int)Xall.size() - 1;\n                else if (pattern == 2) sel = (int)Xall.size() / 2;\n                else sel = ((int)Xall.size() - 1) / 2;\n                int x = Xall[sel];\n                for (int y : Y) cand.occ[idx3(x, y, z)] = 1;\n            } else {\n                int p = (int)Y.size(), k = (int)Xreq.size();\n                for (int g = 0; g < k; g++) {\n                    int l = (long long)g * p / k;\n                    int r = (long long)(g + 1) * p / k;\n                    int x = Xreq[g];\n                    for (int i = l; i < r; i++) {\n                        cand.occ[idx3(x, Y[i], z)] = 1;\n                    }\n                }\n            }\n        }\n    }\n\n    extract_shape_components(cand.occ, cand.comps);\n    return cand;\n}\n\nvoid extract_segments_axis(const array<uint8_t, MAXN>& occ, int axis, vector<LineSeg>& segs) {\n    segs.clear();\n\n    if (axis == 0) {\n        for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int x = 0;\n            while (x < D) {\n                while (x < D && !occ[idx3(x, y, z)]) x++;\n                if (x == D) break;\n                int x0 = x;\n                while (x < D && occ[idx3(x, y, z)]) x++;\n                segs.push_back({0, x0, y, z, x - x0});\n            }\n        }\n    } else if (axis == 1) {\n        for (int x = 0; x < D; x++) for (int z = 0; z < D; z++) {\n            int y = 0;\n            while (y < D) {\n                while (y < D && !occ[idx3(x, y, z)]) y++;\n                if (y == D) break;\n                int y0 = y;\n                while (y < D && occ[idx3(x, y, z)]) y++;\n                segs.push_back({1, x, y0, z, y - y0});\n            }\n        }\n    } else {\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) {\n            int z = 0;\n            while (z < D) {\n                while (z < D && !occ[idx3(x, y, z)]) z++;\n                if (z == D) break;\n                int z0 = z;\n                while (z < D && occ[idx3(x, y, z)]) z++;\n                segs.push_back({2, x, y, z0, z - z0});\n            }\n        }\n    }\n}\n\nlong double match_score_lengths(const vector<LineSeg>& s1, const vector<LineSeg>& s2) {\n    priority_queue<int> pq1, pq2;\n    for (auto &s : s1) pq1.push(s.len);\n    for (auto &s : s2) pq2.push(s.len);\n\n    long double sc = 0.0L;\n    long long exclusive = 0;\n\n    while (!pq1.empty() && !pq2.empty()) {\n        int a = pq1.top(); pq1.pop();\n        int b = pq2.top(); pq2.pop();\n        int m = min(a, b);\n        sc += 1.0L / (long double)m;\n        if (a > m) pq1.push(a - m);\n        if (b > m) pq2.push(b - m);\n    }\n    while (!pq1.empty()) {\n        exclusive += pq1.top();\n        pq1.pop();\n    }\n    while (!pq2.empty()) {\n        exclusive += pq2.top();\n        pq2.pop();\n    }\n    sc += (long double)exclusive;\n    return sc;\n}\n\nPairPlan make_pair_plan(const Candidate& c1, const Candidate& c2) {\n    PairPlan plan;\n\n    unordered_map<string, vector<int>> mp1, mp2;\n    mp1.reserve(c1.comps.size() * 2 + 1);\n    mp2.reserve(c2.comps.size() * 2 + 1);\n\n    for (int i = 0; i < (int)c1.comps.size(); i++) mp1[c1.comps[i].sig].push_back(i);\n    for (int i = 0; i < (int)c2.comps.size(); i++) mp2[c2.comps[i].sig].push_back(i);\n\n    vector<char> used1(c1.comps.size(), 0), used2(c2.comps.size(), 0);\n\n    for (auto &kv : mp1) {\n        auto it = mp2.find(kv.first);\n        if (it == mp2.end()) continue;\n        int cnt = min((int)kv.second.size(), (int)it->second.size());\n        for (int t = 0; t < cnt; t++) {\n            int i = kv.second[t];\n            int j = it->second[t];\n            used1[i] = 1;\n            used2[j] = 1;\n            plan.matchedExtra.push_back({i, j});\n            plan.extraScore += 1.0L / (long double)c1.comps[i].vol;\n        }\n    }\n\n    array<uint8_t, MAXN> res1{}, res2{};\n    res1.fill(0);\n    res2.fill(0);\n\n    for (int i = 0; i < (int)c1.comps.size(); i++) if (!used1[i]) {\n        for (int id : c1.comps[i].cells) res1[id] = 1;\n    }\n    for (int i = 0; i < (int)c2.comps.size(); i++) if (!used2[i]) {\n        for (int id : c2.comps[i].cells) res2[id] = 1;\n    }\n\n    vector<LineSeg> seg1[3], seg2[3];\n    for (int a = 0; a < 3; a++) {\n        extract_segments_axis(res1, a, seg1[a]);\n        extract_segments_axis(res2, a, seg2[a]);\n    }\n\n    long double bestRes = 1e100L;\n    int bestA1 = 2, bestA2 = 2;\n    for (int a1 = 0; a1 < 3; a1++) for (int a2 = 0; a2 < 3; a2++) {\n        long double sc = match_score_lengths(seg1[a1], seg2[a2]);\n        if (sc < bestRes) {\n            bestRes = sc;\n            bestA1 = a1;\n            bestA2 = a2;\n        }\n    }\n\n    plan.axis1 = bestA1;\n    plan.axis2 = bestA2;\n    plan.extraScore += bestRes;\n    return plan;\n}\n\nvector<int> select_thresholds() {\n    vector<int> u;\n    for (auto &c : commonComps) u.push_back(c.vol);\n    sort(u.begin(), u.end());\n    u.erase(unique(u.begin(), u.end()), u.end());\n\n    vector<int> th;\n    auto add = [&](int v) {\n        if (find(th.begin(), th.end(), v) == th.end()) th.push_back(v);\n    };\n\n    add(-1); // keep all common components\n\n    if (u.empty()) {\n        sort(th.begin(), th.end());\n        return th;\n    }\n\n    int m = (int)u.size();\n    for (int i = 0; i < min(m, 6); i++) add(u[i] - 1);\n    add(u[m / 4] - 1);\n    add(u[m / 2] - 1);\n    add(u[(3 * m) / 4] - 1);\n    add(u.back() - 1);\n    add(u.back()); // keep none\n\n    sort(th.begin(), th.end());\n    th.erase(unique(th.begin(), th.end()), th.end());\n    return th;\n}\n\nstring occ_key(const array<uint8_t, MAXN>& occ) {\n    return string(reinterpret_cast<const char*>(occ.data()), Ncells);\n}\n\nEvalResult evaluate_core(const CoreInfo& core, const vector<Param>& dpParams, double timeLimit) {\n    EvalResult res;\n    build_runs(core);\n\n    vector<Candidate> cand[2];\n\n    for (int obj = 0; obj < 2; obj++) {\n        unordered_set<string> seen;\n        seen.reserve(32);\n\n        auto push_candidate = [&](Candidate&& c) {\n            string key = occ_key(c.occ);\n            if (seen.insert(key).second) cand[obj].push_back(std::move(c));\n        };\n\n        for (auto &prm : dpParams) {\n            if (elapsed_sec() > timeLimit && !cand[obj].empty()) break;\n            push_candidate(build_candidate_dp(obj, core, prm));\n        }\n\n        for (int pat = 0; pat < 4; pat++) {\n            if (elapsed_sec() > timeLimit && !cand[obj].empty()) break;\n            push_candidate(build_candidate_group(obj, core, pat));\n        }\n\n        if (cand[obj].empty()) {\n            push_candidate(build_candidate_dp(obj, core, dpParams[0]));\n        }\n    }\n\n    for (auto &c1 : cand[0]) {\n        if (elapsed_sec() > timeLimit + 0.05) break;\n        for (auto &c2 : cand[1]) {\n            PairPlan plan = make_pair_plan(c1, c2);\n            long double sc = core.scoreCore + plan.extraScore;\n            if (!res.ok || sc < res.score) {\n                res.ok = true;\n                res.score = sc;\n                res.c1 = c1;\n                res.c2 = c2;\n                res.plan = std::move(plan);\n            }\n        }\n    }\n\n    return res;\n}\n\nvoid fill_line_seg(array<int, MAXN>& out, LineSeg s, int len, int label) {\n    for (int t = 0; t < len; t++) {\n        int x = s.x, y = s.y, z = s.z;\n        if (s.axis == 0) x += t;\n        else if (s.axis == 1) y += t;\n        else z += t;\n        out[idx3(x, y, z)] = label;\n    }\n}\nvoid advance_seg(LineSeg& s, int used) {\n    if (s.axis == 0) s.x += used;\n    else if (s.axis == 1) s.y += used;\n    else s.z += used;\n    s.len -= used;\n}\n\nvoid assign_final_labels(\n    const CoreInfo& core,\n    const Candidate& cand1,\n    const Candidate& cand2,\n    const PairPlan& plan,\n    array<int, MAXN>& out1,\n    array<int, MAXN>& out2,\n    int& nblocks\n) {\n    out1.fill(0);\n    out2.fill(0);\n    nblocks = 0;\n\n    // shared exact common-core components\n    for (int cid = 0; cid < (int)commonComps.size(); cid++) {\n        if (!core.keep[cid]) continue;\n        ++nblocks;\n        for (int id : commonComps[cid].cells) {\n            out1[id] = nblocks;\n            out2[id] = nblocks;\n        }\n    }\n\n    // shared identical extra connected components\n    vector<char> used1(cand1.comps.size(), 0), used2(cand2.comps.size(), 0);\n    for (auto [i, j] : plan.matchedExtra) {\n        used1[i] = 1;\n        used2[j] = 1;\n        ++nblocks;\n        for (int id : cand1.comps[i].cells) out1[id] = nblocks;\n        for (int id : cand2.comps[j].cells) out2[id] = nblocks;\n    }\n\n    array<uint8_t, MAXN> res1{}, res2{};\n    res1.fill(0);\n    res2.fill(0);\n    for (int i = 0; i < (int)cand1.comps.size(); i++) if (!used1[i]) {\n        for (int id : cand1.comps[i].cells) res1[id] = 1;\n    }\n    for (int i = 0; i < (int)cand2.comps.size(); i++) if (!used2[i]) {\n        for (int id : cand2.comps[i].cells) res2[id] = 1;\n    }\n\n    vector<LineSeg> s1, s2;\n    extract_segments_axis(res1, plan.axis1, s1);\n    extract_segments_axis(res2, plan.axis2, s2);\n\n    priority_queue<LineSeg, vector<LineSeg>, LineSegCmp> pq1, pq2;\n    for (auto &s : s1) pq1.push(s);\n    for (auto &s : s2) pq2.push(s);\n\n    while (!pq1.empty() && !pq2.empty()) {\n        LineSeg a = pq1.top(); pq1.pop();\n        LineSeg b = pq2.top(); pq2.pop();\n        int m = min(a.len, b.len);\n        ++nblocks;\n        fill_line_seg(out1, a, m, nblocks);\n        fill_line_seg(out2, b, m, nblocks);\n\n        if (a.len > m) {\n            advance_seg(a, m);\n            pq1.push(a);\n        }\n        if (b.len > m) {\n            advance_seg(b, m);\n            pq2.push(b);\n        }\n    }\n    while (!pq1.empty()) {\n        LineSeg a = pq1.top(); pq1.pop();\n        ++nblocks;\n        fill_line_seg(out1, a, a.len, nblocks);\n    }\n    while (!pq2.empty()) {\n        LineSeg b = pq2.top(); pq2.pop();\n        ++nblocks;\n        fill_line_seg(out2, b, b.len, nblocks);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> D;\n    Ncells = D * D * D;\n    init_rotations();\n\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) cin >> fstr[i][z];\n        for (int z = 0; z < D; z++) cin >> rstr[i][z];\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        for (int z = 0; z < D; z++) {\n            actXMask[obj][z] = 0;\n            actYMask[obj][z] = 0;\n            actXList[obj][z].clear();\n            actYList[obj][z].clear();\n\n            for (int x = 0; x < D; x++) {\n                if (fstr[obj][z][x] == '1') {\n                    actXMask[obj][z] |= (uint16_t(1) << x);\n                    actXList[obj][z].push_back(x);\n                }\n            }\n            for (int y = 0; y < D; y++) {\n                if (rstr[obj][z][y] == '1') {\n                    actYMask[obj][z] |= (uint16_t(1) << y);\n                    actYList[obj][z].push_back(y);\n                }\n            }\n\n            for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) {\n                activeCell[obj][x][y][z] =\n                    (fstr[obj][z][x] == '1' && rstr[obj][z][y] == '1') ? 1 : 0;\n            }\n        }\n    }\n\n    build_full_common_components();\n\n    vector<Param> dpParams = {\n        {+1, 100000,    0, 1},\n        {-1, 100000,    0, 1},\n        {+1,  25000,  200, 2},\n        {-1,  25000,  200, 2},\n        {+1,   6000, 1200, 3},\n        {-1,   6000, 1200, 3},\n    };\n\n    vector<int> thresholds = select_thresholds();\n\n    long double bestScore = 1e100L;\n    CoreInfo bestCore;\n    Candidate bestCand1, bestCand2;\n    PairPlan bestPlan;\n    bool found = false;\n\n    vector<CoreInfo> cores;\n    for (int th : thresholds) cores.push_back(build_core_by_threshold(th));\n\n    sort(cores.begin(), cores.end(), [&](const CoreInfo& a, const CoreInfo& b) {\n        long double la = a.scoreCore + (long double)abs(a.remVol[0] - a.remVol[1]);\n        long double lb = b.scoreCore + (long double)abs(b.remVol[0] - b.remVol[1]);\n        return la < lb;\n    });\n\n    for (const CoreInfo& core : cores) {\n        if (elapsed_sec() > 5.15) break;\n        long double lb = core.scoreCore + (long double)abs(core.remVol[0] - core.remVol[1]);\n        if (found && lb >= bestScore - 1e-15L) continue;\n\n        EvalResult ev = evaluate_core(core, dpParams, 5.45);\n        if (ev.ok && (!found || ev.score < bestScore)) {\n            found = true;\n            bestScore = ev.score;\n            bestCore = core;\n            bestCand1 = std::move(ev.c1);\n            bestCand2 = std::move(ev.c2);\n            bestPlan = std::move(ev.plan);\n        }\n    }\n\n    if (!found) {\n        CoreInfo core = build_core_by_threshold((int)1e9);\n        EvalResult ev = evaluate_core(core, dpParams, 5.45);\n        if (ev.ok) {\n            found = true;\n            bestScore = ev.score;\n            bestCore = core;\n            bestCand1 = std::move(ev.c1);\n            bestCand2 = std::move(ev.c2);\n            bestPlan = std::move(ev.plan);\n        } else {\n            // ultra-fallback\n            bestCore = core;\n            bestCand1 = build_candidate_dp(0, core, dpParams[0]);\n            bestCand2 = build_candidate_dp(1, core, dpParams[0]);\n            bestPlan = make_pair_plan(bestCand1, bestCand2);\n        }\n    }\n\n    // 1-flip local search around the best threshold solution\n    if (!commonComps.empty() && elapsed_sec() < 5.6) {\n        vector<int> ord(commonComps.size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (commonComps[a].vol != commonComps[b].vol) return commonComps[a].vol < commonComps[b].vol;\n            return a < b;\n        });\n        if ((int)ord.size() > 32) ord.resize(32);\n\n        vector<int> ordRev = ord;\n        reverse(ordRev.begin(), ordRev.end());\n\n        vector<char> curKeep = bestCore.keep;\n\n        for (int phase = 0; phase < 2 && elapsed_sec() < 5.8; phase++) {\n            const vector<int>& order = (phase == 0 ? ord : ordRev);\n            bool improved = false;\n\n            for (int cid : order) {\n                if (elapsed_sec() > 5.85) break;\n\n                vector<char> nk = curKeep;\n                nk[cid] ^= 1;\n                CoreInfo nc = build_core_from_keep(nk);\n                long double lb = nc.scoreCore + (long double)abs(nc.remVol[0] - nc.remVol[1]);\n                if (lb >= bestScore - 1e-15L) continue;\n\n                EvalResult ev = evaluate_core(nc, dpParams, 5.9);\n                if (ev.ok && ev.score + 1e-15L < bestScore) {\n                    improved = true;\n                    curKeep = std::move(nk);\n                    bestScore = ev.score;\n                    bestCore = nc;\n                    bestCand1 = std::move(ev.c1);\n                    bestCand2 = std::move(ev.c2);\n                    bestPlan = std::move(ev.plan);\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    array<int, MAXN> out1, out2;\n    int nblocks = 0;\n    assign_final_labels(bestCore, bestCand1, bestCand2, bestPlan, out1, out2, nblocks);\n\n    cout << nblocks << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out2[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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 leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n};\n\nstruct Candidate {\n    vector<int> P;\n    vector<char> B;\n    int covered = -1;\n    long long cost = (1LL << 62);\n};\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> B;\n};\n\nclass Solver {\npublic:\n    int N, M, K;\n    vector<int> xs, ys;\n    vector<Edge> edges;\n    vector<int> as, bs;\n\n    vector<vector<int>> req; // req[i][k] = minimum power to cover resident k, or 5001\n    vector<vector<pair<int,int>>> lists; // (required power, resident id), sorted\n    vector<vector<int>> incident;\n    vector<vector<int>> eidMat;\n\n    vector<vector<long long>> sp;\n    vector<vector<int>> nxt;\n\n    chrono::steady_clock::time_point t0;\n    static constexpr long long INF64 = (1LL << 60);\n    static constexpr double HARD_LIMIT = 1.92;\n\n    void input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> K;\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n        edges.resize(M);\n        incident.assign(N, {});\n        eidMat.assign(N, vector<int>(N, -1));\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, v, w};\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            eidMat[u][v] = eidMat[v][u] = i;\n        }\n\n        as.resize(K);\n        bs.resize(K);\n        for (int k = 0; k < K; k++) cin >> as[k] >> bs[k];\n    }\n\n    double elapsed() const {\n        auto t = chrono::steady_clock::now();\n        return chrono::duration<double>(t - t0).count();\n    }\n\n    static int ceil_sqrt_ll(long long x) {\n        long long r = sqrt((long double)x);\n        while (r * r < x) ++r;\n        while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n        return (int)r;\n    }\n\n    void precompute() {\n        req.assign(N, vector<int>(K, 5001));\n        lists.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            lists[i].reserve(K / 2);\n            for (int k = 0; k < K; k++) {\n                long long dx = (long long)xs[i] - as[k];\n                long long dy = (long long)ys[i] - bs[k];\n                long long d2 = dx * dx + dy * dy;\n                int r = ceil_sqrt_ll(d2);\n                if (r <= 5000) {\n                    req[i][k] = r;\n                    lists[i].push_back({r, k});\n                }\n            }\n            sort(lists[i].begin(), lists[i].end());\n        }\n\n        sp.assign(N, vector<long long>(N, INF64));\n        nxt.assign(N, vector<int>(N, -1));\n        for (int i = 0; i < N; i++) {\n            sp[i][i] = 0;\n            nxt[i][i] = i;\n        }\n        for (int e = 0; e < M; e++) {\n            auto [u, v, w] = edges[e];\n            if (w < sp[u][v]) {\n                sp[u][v] = sp[v][u] = w;\n                nxt[u][v] = v;\n                nxt[v][u] = u;\n            }\n        }\n        for (int k = 0; k < N; k++) {\n            for (int i = 0; i < N; i++) if (sp[i][k] < INF64) {\n                for (int j = 0; j < N; j++) if (sp[k][j] < INF64) {\n                    long long nd = sp[i][k] + sp[k][j];\n                    if (nd < sp[i][j]) {\n                        sp[i][j] = nd;\n                        nxt[i][j] = nxt[i][k];\n                    }\n                }\n            }\n        }\n\n        t0 = chrono::steady_clock::now();\n    }\n\n    vector<long double> make_gain_table(long double gamma) const {\n        vector<long double> gain(K + 1, 0);\n        if (fabsl(gamma - 1.0L) < 1e-18L) {\n            for (int i = 1; i <= K; i++) gain[i] = (long double)i;\n        } else {\n            for (int i = 1; i <= K; i++) gain[i] = powl((long double)i, gamma);\n        }\n        return gain;\n    }\n\n    vector<int> reconstruct_path_vertices(int s, int t) const {\n        vector<int> path;\n        if (nxt[s][t] == -1) return path;\n        int cur = s;\n        path.push_back(cur);\n        while (cur != t) {\n            cur = nxt[cur][t];\n            path.push_back(cur);\n        }\n        return path;\n    }\n\n    void recompute_nearest_tree(\n        const vector<char>& inTree,\n        vector<long long>& distToTree,\n        vector<int>& nearTree\n    ) const {\n        distToTree.assign(N, INF64);\n        nearTree.assign(N, -1);\n        for (int i = 0; i < N; i++) {\n            if (inTree[i]) {\n                distToTree[i] = 0;\n                nearTree[i] = i;\n                continue;\n            }\n            long long best = INF64;\n            int bestv = -1;\n            for (int v = 0; v < N; v++) if (inTree[v]) {\n                if (sp[v][i] < best) {\n                    best = sp[v][i];\n                    bestv = v;\n                }\n            }\n            distToTree[i] = best;\n            nearTree[i] = bestv;\n        }\n    }\n\n    long long edge_cost(const vector<char>& B) const {\n        long long c = 0;\n        for (int i = 0; i < M; i++) if (B[i]) c += edges[i].w;\n        return c;\n    }\n\n    long long power_cost(const vector<int>& P) const {\n        long long c = 0;\n        for (int i = 0; i < N; i++) c += 1LL * P[i] * P[i];\n        return c;\n    }\n\n    vector<char> terminals_from_P(const vector<int>& P) const {\n        vector<char> term(N, 0);\n        term[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) term[i] = 1;\n        return term;\n    }\n\n    vector<char> tree_vertices(const vector<char>& B) const {\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 (int eid : incident[v]) if (B[eid]) {\n                int to = edges[eid].u ^ edges[eid].v ^ v;\n                if (!vis[to]) {\n                    vis[to] = 1;\n                    q.push(to);\n                }\n            }\n        }\n        return vis;\n    }\n\n    vector<int> degrees_from_B(const vector<char>& B) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        return deg;\n    }\n\n    void prune_nonterminal_leaves(vector<char>& B, const vector<char>& terminal) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n\n        queue<int> q;\n        for (int v = 0; v < N; v++) {\n            if (v != 0 && !terminal[v] && deg[v] == 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            if (v == 0 || terminal[v] || deg[v] != 1) continue;\n\n            int remE = -1, to = -1;\n            for (int eid : incident[v]) if (B[eid]) {\n                remE = eid;\n                to = edges[eid].u ^ edges[eid].v ^ v;\n                break;\n            }\n            if (remE == -1) continue;\n\n            B[remE] = 0;\n            deg[v]--;\n            deg[to]--;\n            if (to != 0 && !terminal[to] && deg[to] == 1) q.push(to);\n        }\n    }\n\n    vector<char> build_tree_metric(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n\n        vector<int> ids;\n        ids.push_back(0);\n        for (int i = 1; i < N; i++) if (terminal[i]) ids.push_back(i);\n\n        int T = (int)ids.size();\n        if (T <= 1) return used;\n\n        // Prim on metric closure.\n        vector<long long> minD(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> vis(T, 0);\n        minD[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            for (int i = 0; i < T; i++) {\n                if (!vis[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            vis[v] = 1;\n            for (int u = 0; u < T; u++) if (!vis[u]) {\n                if (sp[ids[v]][ids[u]] < minD[u]) {\n                    minD[u] = sp[ids[v]][ids[u]];\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<char> cand(M, 0);\n        vector<int> candEdges;\n        for (int i = 1; i < T; i++) {\n            auto path = reconstruct_path_vertices(ids[i], ids[par[i]]);\n            for (int j = 0; j + 1 < (int)path.size(); j++) {\n                int a = path[j], b = path[j + 1];\n                int eid = eidMat[a][b];\n                if (eid >= 0 && !cand[eid]) {\n                    cand[eid] = 1;\n                    candEdges.push_back(eid);\n                }\n            }\n        }\n\n        sort(candEdges.begin(), candEdges.end(), [&](int e1, int e2) {\n            if (edges[e1].w != edges[e2].w) return edges[e1].w < edges[e2].w;\n            return e1 < e2;\n        });\n\n        DSU dsu(N);\n        for (int eid : candEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            if (dsu.merge(u, v)) used[eid] = 1;\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_sph(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n        vector<char> inTree(N, 0);\n        vector<char> left = terminal;\n        inTree[0] = 1;\n        left[0] = 0;\n\n        int rem = 0;\n        for (int i = 0; i < N; i++) if (left[i]) rem++;\n\n        if (rem == 0) return used;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        while (rem > 0) {\n            int best = -1;\n            long long bestD = INF64;\n            for (int i = 0; i < N; i++) if (left[i]) {\n                if (distToTree[i] < bestD) {\n                    bestD = distToTree[i];\n                    best = i;\n                }\n            }\n            if (best == -1) break;\n\n            int from = nearTree[best];\n            auto path = reconstruct_path_vertices(from, best);\n\n            int lastTreeIdx = 0;\n            for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n            for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                int u = path[i], v = path[i + 1];\n                int eid = eidMat[u][v];\n                if (eid >= 0) used[eid] = 1;\n                inTree[u] = 1;\n                inTree[v] = 1;\n            }\n            left[best] = 0;\n            rem--;\n\n            recompute_nearest_tree(inTree, distToTree, nearTree);\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_best(const vector<char>& terminal) const {\n        auto b1 = build_tree_metric(terminal);\n        auto b2 = build_tree_sph(terminal);\n        if (edge_cost(b2) < edge_cost(b1)) return b2;\n        return b1;\n    }\n\n    Candidate make_candidate(const vector<int>& Pin, const vector<char>& Bin) const {\n        vector<int> P = Pin;\n        vector<char> B = Bin;\n\n        // Remove disconnected parts.\n        vector<char> reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n        for (int e = 0; e < M; e++) if (B[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (!(reach[u] && reach[v])) B[e] = 0;\n        }\n\n        vector<char> terminal(N, 0);\n        terminal[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) terminal[i] = 1;\n        prune_nonterminal_leaves(B, terminal);\n\n        reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (reach[i] && P[i] > 0) active.push_back(i);\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n\n        long long cost = power_cost(P) + edge_cost(B);\n        return {P, B, cov, cost};\n    }\n\n    static bool better(const Candidate& a, const Candidate& b, int K) {\n        if (a.covered != b.covered) return a.covered > b.covered;\n        if (a.covered == K) return a.cost < b.cost;\n        return a.cost < b.cost;\n    }\n\n    int count_covered_by_P(const vector<int>& P) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        if (active.empty()) return 0;\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n        return cov;\n    }\n\n    bool covers_need(const vector<int>& P, const vector<char>& need) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (need[k]) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n        return true;\n    }\n\n    void reduce_powers(vector<int>& P, const vector<char>& allowed) const {\n        while (true) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) {\n                if (allowed[i] && P[i] > 0) active.push_back(i);\n            }\n            sort(active.begin(), active.end(), [&](int a, int b) {\n                if (P[a] != P[b]) return P[a] > P[b];\n                return a < b;\n            });\n\n            bool changed = false;\n            for (int i : active) {\n                int newP = 0;\n                for (const auto& [d, rid] : lists[i]) {\n                    if (d > P[i]) break;\n                    bool other = false;\n                    for (int j : active) {\n                        if (j == i || P[j] == 0) continue;\n                        if (req[j][rid] <= P[j]) {\n                            other = true;\n                            break;\n                        }\n                    }\n                    if (!other) newP = d;\n                }\n                if (newP < P[i]) {\n                    P[i] = newP;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    vector<int> greedy_cover_subset(\n        const vector<char>& allowed,\n        const vector<int>& Pinit,\n        const vector<char>& needMask,\n        long double gamma,\n        int banned = -1\n    ) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P = Pinit;\n        vector<char> uncoveredNeed = needMask;\n\n        int rem = 0;\n        for (int k = 0; k < K; k++) if (needMask[k]) rem++;\n\n        if (rem == 0) return P;\n\n        // Remove already-covered needed residents.\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (uncoveredNeed[k]) {\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    uncoveredNeed[k] = 0;\n                    rem--;\n                    break;\n                }\n            }\n        }\n        if (rem == 0) return P;\n\n        vector<int> curPos(N, 0);\n        for (int i = 0; i < N; i++) {\n            auto it = upper_bound(lists[i].begin(), lists[i].end(),\n                                  make_pair(P[i], INT_MAX));\n            curPos[i] = (int)(it - lists[i].begin());\n        }\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                if (!allowed[i] || i == banned) continue;\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (uncoveredNeed[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq);\n                    long double metric = num / gain[newcov];\n\n                    bool take = false;\n                    if (metric < bestMetric - 1e-18L) take = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) take = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) take = true;\n                    }\n\n                    if (take) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (uncoveredNeed[rid]) {\n                    uncoveredNeed[rid] = 0;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return P;\n    }\n\n    vector<int> greedy_on_allowed_gamma(const vector<char>& allowed, long double gamma, int banned = -1) const {\n        vector<int> P0(N, 0);\n        vector<char> need(K, 1);\n        return greedy_cover_subset(allowed, P0, need, gamma, banned);\n    }\n\n    InitialState greedy_initial(long double alpha, long double gamma) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P(N, 0);\n        vector<int> curPos(N, 0);\n        vector<char> covered(K, 0);\n        vector<char> usedEdge(M, 0);\n        vector<char> inTree(N, 0);\n        inTree[0] = 1;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        int rem = K;\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                long double conn = inTree[i] ? 0.0L : alpha * (long double)distToTree[i];\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (!covered[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq) + conn;\n                    long double metric = num / gain[newcov];\n\n                    bool better = false;\n                    if (metric < bestMetric - 1e-18L) better = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) better = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) better = true;\n                    }\n                    if (better) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            if (!inTree[bestStation]) {\n                int from = nearTree[bestStation];\n                auto path = reconstruct_path_vertices(from, bestStation);\n\n                int lastTreeIdx = 0;\n                for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n                for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                    int u = path[i], v = path[i + 1];\n                    int eid = eidMat[u][v];\n                    if (eid >= 0) usedEdge[eid] = 1;\n                    inTree[u] = 1;\n                    inTree[v] = 1;\n                }\n\n                recompute_nearest_tree(inTree, distToTree, nearTree);\n            }\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (!covered[rid]) {\n                    covered[rid] = 1;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return {P, usedEdge};\n    }\n\n    Candidate basic_improve(Candidate cur, int rounds) const {\n        for (int it = 0; it < rounds; it++) {\n            if (elapsed() > HARD_LIMIT) break;\n\n            Candidate bestRound = cur;\n\n            auto B0 = build_tree_best(terminals_from_P(cur.P));\n            Candidate c0 = make_candidate(cur.P, B0);\n            if (better(c0, bestRound, K)) bestRound = c0;\n\n            vector<char> allowed = tree_vertices(bestRound.B);\n\n            static const long double gammas[] = {1.0L, 1.10L};\n            for (long double g : gammas) {\n                if (elapsed() > HARD_LIMIT) break;\n                vector<int> P = greedy_on_allowed_gamma(allowed, g);\n                if (count_covered_by_P(P) < K) continue;\n                reduce_powers(P, allowed);\n                auto B = build_tree_best(terminals_from_P(P));\n                Candidate c = make_candidate(P, B);\n                if (better(c, bestRound, K)) bestRound = c;\n            }\n\n            if (better(bestRound, cur, K)) cur = bestRound;\n            else break;\n        }\n        return cur;\n    }\n\n    Candidate try_remove_station(const Candidate& cur, const vector<char>& allowed, int s) const {\n        Candidate best = cur;\n        if (cur.P[s] == 0) return best;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n\n        vector<char> need(K, 0);\n        int needCnt = 0;\n        for (int k = 0; k < K; k++) {\n            if (req[s][k] > cur.P[s]) continue;\n            bool other = false;\n            for (int i : active) {\n                if (i == s) continue;\n                if (req[i][k] <= cur.P[i]) {\n                    other = true;\n                    break;\n                }\n            }\n            if (!other) {\n                need[k] = 1;\n                needCnt++;\n            }\n        }\n\n        vector<int> baseP = cur.P;\n        baseP[s] = 0;\n\n        auto relax_from_P = [&](vector<int> P) {\n            if (elapsed() > HARD_LIMIT) return;\n            if (count_covered_by_P(P) < K) return;\n            reduce_powers(P, allowed);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate c = make_candidate(P, B);\n            if (better(c, best, K)) best = c;\n        };\n\n        if (needCnt == 0) {\n            relax_from_P(baseP);\n        } else {\n            vector<int> P1 = greedy_cover_subset(allowed, baseP, need, 1.0L, s);\n            if (covers_need(P1, need)) relax_from_P(P1);\n\n            if (elapsed() <= HARD_LIMIT) {\n                vector<int> P2 = greedy_cover_subset(allowed, baseP, need, 1.10L, s);\n                if (covers_need(P2, need)) relax_from_P(P2);\n            }\n        }\n\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P3 = greedy_on_allowed_gamma(allowed, 1.0L, s);\n            relax_from_P(P3);\n        }\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P4 = greedy_on_allowed_gamma(allowed, 1.10L, s);\n            relax_from_P(P4);\n        }\n\n        return best;\n    }\n\n    Candidate local_remove(Candidate cur) const {\n        while (elapsed() < HARD_LIMIT) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n            if (active.empty()) break;\n\n            vector<char> allowed = tree_vertices(cur.B);\n            vector<int> deg = degrees_from_B(cur.B);\n\n            vector<int> byPower = active;\n            sort(byPower.begin(), byPower.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> leafs;\n            for (int v : active) if (deg[v] == 1) leafs.push_back(v);\n            sort(leafs.begin(), leafs.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> trials;\n            auto push_unique = [&](int v) {\n                for (int x : trials) if (x == v) return;\n                trials.push_back(v);\n            };\n\n            for (int i = 0; i < (int)leafs.size() && i < 6; i++) push_unique(leafs[i]);\n            for (int i = 0; i < (int)byPower.size() && i < 8; i++) push_unique(byPower[i]);\n\n            bool improved = false;\n            for (int s : trials) {\n                if (elapsed() > HARD_LIMIT) break;\n                Candidate cand = try_remove_station(cur, allowed, s);\n                if (better(cand, cur, K)) {\n                    cur = basic_improve(cand, 1);\n                    improved = true;\n                    break;\n                }\n            }\n            if (!improved) break;\n        }\n        return cur;\n    }\n\n    Candidate solve() {\n        Candidate best;\n\n        auto consider = [&](Candidate c, int rounds = 3) {\n            if (elapsed() > HARD_LIMIT) return;\n            c = basic_improve(c, rounds);\n            if (better(c, best, K)) best = c;\n        };\n\n        vector<pair<long double,long double>> connectedParams = {\n            {0.00L, 1.00L},\n            {0.20L, 1.00L},\n            {0.55L, 1.00L},\n            {1.00L, 1.00L},\n            {0.35L, 1.12L},\n        };\n\n        for (auto [alpha, gamma] : connectedParams) {\n            if (elapsed() > 1.05) break;\n            InitialState init = greedy_initial(alpha, gamma);\n            Candidate cand = make_candidate(init.P, init.B);\n            consider(cand, 3);\n        }\n\n        vector<char> allAllowed(N, 1);\n        vector<long double> globalGammas = {0.92L, 1.00L, 1.10L, 1.18L};\n\n        for (long double g : globalGammas) {\n            if (elapsed() > 1.45) break;\n            vector<int> P = greedy_on_allowed_gamma(allAllowed, g);\n            if (count_covered_by_P(P) < K) continue;\n            reduce_powers(P, allAllowed);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate cand = make_candidate(P, B);\n            consider(cand, 3);\n        }\n\n        // Fallback if somehow empty.\n        if (best.covered < 0) {\n            vector<int> P(N, 0);\n            vector<char> B(M, 0);\n            best = make_candidate(P, B);\n        }\n\n        if (elapsed() < 1.72) best = basic_improve(best, 2);\n        if (elapsed() < 1.86) best = local_remove(best);\n        if (elapsed() < HARD_LIMIT) best = basic_improve(best, 2);\n\n        return best;\n    }\n\n    void output(const Candidate& ans) const {\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans.P[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << int(ans.B[i]);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.input();\n    solver.precompute();\n    Candidate ans = solver.solve();\n    solver.output(ans);\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;\nusing ll = long long;\nusing Board = array<array<int, N>, N>;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    int E = 0;\n\n    long long score_like() const {\n        if ((int)ops.size() > 10000) return -(1LL << 60);\n        if (E == 0) return 100000LL - 5LL * (int)ops.size();\n        return 50000LL - 50LL * E;\n    }\n};\n\nint desired_row[M];\nint noise_tbl[4][N][N];\n\nuint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nvoid prepare_globals() {\n    for (int r = 0; r < N; ++r) {\n        int L = r * (r + 1) / 2;\n        int R = (r + 1) * (r + 2) / 2 - 1;\n        for (int v = L; v <= R && v < M; ++v) desired_row[v] = r;\n    }\n    for (int s = 0; s < 4; ++s) {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                uint64_t h = splitmix64(123456789ULL + 1000003ULL * s + 1009ULL * x + y);\n                noise_tbl[s][x][y] = (int)(h % 15) - 7; // [-7, 7]\n            }\n        }\n    }\n}\n\ninline int vid(int x, int y) {\n    return x * (x + 1) / 2 + y;\n}\n\nint count_violations(const Board& a) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++E;\n            if (a[x][y] > a[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nBoard reflect_board(const Board& a) {\n    Board b{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            b[x][y] = a[x][x - y];\n        }\n    }\n    return b;\n}\n\nvector<Op> reflect_ops(vector<Op> ops) {\n    for (auto& op : ops) {\n        op.y1 = op.x1 - op.y1;\n        op.y2 = op.x2 - op.y2;\n    }\n    return ops;\n}\n\nbool better_candidate(const Candidate& a, const Candidate& b) {\n    if (a.score_like() != b.score_like()) return a.score_like() > b.score_like();\n    if (a.E != b.E) return a.E < b.E;\n    return a.ops.size() < b.ops.size();\n}\n\nvoid apply_ops(Board& b, const vector<Op>& ops) {\n    for (const auto& op : ops) {\n        swap(b[op.x1][op.y1], b[op.x2][op.y2]);\n    }\n}\n\nstruct COp {\n    Op op;\n    int a, b; // sorted vertex ids\n};\n\ninline bool same_edge(const COp& p, const COp& q) {\n    return p.a == q.a && p.b == q.b;\n}\n\ninline bool disjoint_edges(const COp& p, const COp& q) {\n    return p.a != q.a && p.a != q.b && p.b != q.a && p.b != q.b;\n}\n\nvector<Op> compress_once(const vector<Op>& ops) {\n    vector<COp> st;\n    st.reserve(ops.size());\n    for (const auto& op : ops) {\n        int u = vid(op.x1, op.y1);\n        int v = vid(op.x2, op.y2);\n        if (u > v) swap(u, v);\n        st.push_back({op, u, v});\n\n        int i = (int)st.size() - 1;\n        while (i > 0) {\n            if (same_edge(st[i], st[i - 1])) {\n                st.erase(st.begin() + i - 1, st.begin() + i + 1);\n                break;\n            }\n            if (disjoint_edges(st[i], st[i - 1])) {\n                swap(st[i], st[i - 1]);\n                --i;\n            } else {\n                break;\n            }\n        }\n    }\n    vector<Op> res;\n    res.reserve(st.size());\n    for (auto& e : st) res.push_back(e.op);\n    return res;\n}\n\nvector<Op> compress_ops(vector<Op> ops) {\n    // One pass is usually enough; two passes are a safe extra.\n    ops = compress_once(ops);\n    ops = compress_once(ops);\n    return ops;\n}\n\nCandidate normalize_candidate(const Board& init, Candidate c) {\n    c.ops = compress_ops(std::move(c.ops));\n    Board b = init;\n    apply_ops(b, c.ops);\n    c.E = count_violations(b);\n    return c;\n}\n\n/* ---------------- Previous constructive family ---------------- */\n\nstruct Builder {\n    Board a;\n    vector<Op> ops;\n\n    Builder(const Board& init) : a(init) {\n        ops.reserve(10000);\n    }\n\n    static bool reachable_down(int r, int c, int tr, int tc) {\n        if (r > tr) return false;\n        return (c <= tc && tc <= c + (tr - r));\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        swap(a[x1][y1], a[x2][y2]);\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    pair<int,int> find_min_subtriangle(int x, int y) const {\n        int best_v = INT_MAX;\n        pair<int,int> best = {x, y};\n        for (int i = x; i < N; ++i) {\n            int l = y;\n            int r = y + (i - x);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] < best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    pair<int,int> find_max_uppertriangle(int x, int y) const {\n        int best_v = -1;\n        pair<int,int> best = {x, y};\n        for (int i = 0; i <= x; ++i) {\n            int l = max(0, y - (x - i));\n            int r = min(i, y);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] > best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_best_path_top(int tx, int ty, int sx, int sy) const {\n        const int NEG = -1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                dp[i][j] = NEG;\n\n        dp[sx][sy] = 0;\n\n        for (int r = sx - 1; r >= tx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, sx, sy)) continue;\n                int best = NEG;\n                if (reachable_down(r + 1, c, sx, sy) && dp[r + 1][c] != NEG)\n                    best = max(best, dp[r + 1][c]);\n                if (reachable_down(r + 1, c + 1, sx, sy) && dp[r + 1][c + 1] != NEG)\n                    best = max(best, dp[r + 1][c + 1]);\n                if (best != NEG) dp[r][c] = a[r][c] + best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = tx, c = ty;\n        path.push_back({r, c});\n        while (!(r == sx && c == sy)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = NEG;\n\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, sx, sy)) return;\n                if (dp[nr][nc] == NEG) return;\n                if (nxt.first == -1 ||\n                    dp[nr][nc] > best ||\n                    (dp[nr][nc] == best && a[nr][nc] > a[nxt.first][nxt.second])) {\n                    best = dp[nr][nc];\n                    nxt = {nr, nc};\n                }\n            };\n\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back({r, c});\n        }\n        return path;\n    }\n\n    vector<pair<int,int>> build_best_path_bottom(int sx, int sy, int tx, int ty) const {\n        const int INF = 1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i)\n            for (int j = 0; j < N; ++j)\n                dp[i][j] = INF;\n\n        dp[tx][ty] = 0;\n\n        for (int r = tx - 1; r >= sx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, tx, ty)) continue;\n                int best = INF;\n                if (reachable_down(r + 1, c, tx, ty) && dp[r + 1][c] != INF)\n                    best = min(best, a[r + 1][c] + dp[r + 1][c]);\n                if (reachable_down(r + 1, c + 1, tx, ty) && dp[r + 1][c + 1] != INF)\n                    best = min(best, a[r + 1][c + 1] + dp[r + 1][c + 1]);\n                dp[r][c] = best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = sx, c = sy;\n        path.push_back({r, c});\n        while (!(r == tx && c == ty)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = INF;\n\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, tx, ty)) return;\n                if (dp[nr][nc] == INF) return;\n                int cand = a[nr][nc] + dp[nr][nc];\n                if (nxt.first == -1 ||\n                    cand < best ||\n                    (cand == best && a[nr][nc] < a[nxt.first][nxt.second])) {\n                    best = cand;\n                    nxt = {nr, nc};\n                }\n            };\n\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back({r, c});\n        }\n        return path;\n    }\n\n    Candidate solve_topdown() {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_min_subtriangle(x, y);\n                auto path = build_best_path_top(x, y, sx, sy);\n                for (int i = (int)path.size() - 1; i >= 1; --i) {\n                    auto [x1, y1] = path[i];\n                    auto [x2, y2] = path[i - 1];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n\n    Candidate solve_bottomup() {\n        for (int x = N - 1; x >= 0; --x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_max_uppertriangle(x, y);\n                auto path = build_best_path_bottom(sx, sy, x, y);\n                for (int i = 1; i < (int)path.size(); ++i) {\n                    auto [x1, y1] = path[i - 1];\n                    auto [x2, y2] = path[i];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\n/* ---------------- Generalized value-order family ---------------- */\n\nstruct ValueParams {\n    ll W;\n    ll coef_value;\n    ll coef_slack;\n    int noise_id; // -1 means no noise\n};\n\nstruct ValueOrderSolver {\n    Board a;\n    array<int, M> posx{}, posy{};\n    vector<Op> ops;\n\n    ValueParams prm;\n    bool upward;\n    int curv = 0;\n\n    static constexpr ll INF = (1LL << 60);\n\n    ll memo[N][N];\n    bool seen[N][N];\n    int nxtx[N][N], nxty[N][N];\n\n    ValueOrderSolver(const Board& init, ValueParams p, bool up)\n        : a(init), prm(p), upward(up) {\n        ops.reserve(10000);\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                int v = a[x][y];\n                posx[v] = x;\n                posy[v] = y;\n            }\n        }\n    }\n\n    inline ll noise_at(int x, int y) const {\n        if (prm.noise_id < 0) return 0;\n        return noise_tbl[prm.noise_id][x][y];\n    }\n\n    inline ll reward_up(int px, int py) const {\n        int t = a[px][py];\n        int slack = desired_row[t] - px; // positive means \"token still wants to go deeper\"\n        return prm.coef_value * t + prm.coef_slack * slack + noise_at(px, py);\n    }\n\n    inline ll penalty_down(int cx, int cy) const {\n        int t = a[cx][cy];\n        int slack = desired_row[t] - cx; // positive => pulling up is bad\n        return prm.coef_value * t + prm.coef_slack * slack + noise_at(cx, cy);\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        int v1 = a[x1][y1];\n        int v2 = a[x2][y2];\n        swap(a[x1][y1], a[x2][y2]);\n        posx[v1] = x2; posy[v1] = y2;\n        posx[v2] = x1; posy[v2] = y1;\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    ll dfs_up(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        ll bestReward = -(1LL << 60);\n\n        auto consider = [&](int px, int py) {\n            if (a[px][py] <= curv) return;\n            ll rew = reward_up(px, py);\n            ll cand = dfs_up(px, py) + prm.W - rew;\n            if (cand < best ||\n                (cand == best && (rew > bestReward ||\n                                  (rew == bestReward && py < by)))) {\n                best = cand;\n                bx = px; by = py;\n                bestReward = rew;\n            }\n        };\n\n        if (x > 0) {\n            if (y > 0) consider(x - 1, y - 1);\n            if (y < x) consider(x - 1, y);\n        }\n\n        if (bx == -1) best = 0;\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    ll dfs_down(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        ll bestPen = (1LL << 60);\n\n        auto consider = [&](int cx, int cy) {\n            if (a[cx][cy] >= curv) return;\n            ll pen = penalty_down(cx, cy);\n            ll cand = dfs_down(cx, cy) + prm.W + pen;\n            if (cand < best ||\n                (cand == best && (pen < bestPen ||\n                                  (pen == bestPen && cy < by)))) {\n                best = cand;\n                bx = cx; by = cy;\n                bestPen = pen;\n            }\n        };\n\n        if (x + 1 < N) {\n            consider(x + 1, y);\n            consider(x + 1, y + 1);\n        }\n\n        if (bx == -1) best = 0;\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    Candidate run() {\n        if (upward) {\n            for (int v = 0; v < M; ++v) {\n                curv = v;\n                memset(seen, 0, sizeof(seen));\n                int x = posx[v], y = posy[v];\n                dfs_up(x, y);\n                while (nxtx[x][y] != -1) {\n                    int nx = nxtx[x][y], ny = nxty[x][y];\n                    do_swap(x, y, nx, ny);\n                    x = nx; y = ny;\n                    if ((int)ops.size() > 10000) {\n                        return Candidate{ops, count_violations(a)};\n                    }\n                }\n            }\n        } else {\n            for (int v = M - 1; v >= 0; --v) {\n                curv = v;\n                memset(seen, 0, sizeof(seen));\n                int x = posx[v], y = posy[v];\n                dfs_down(x, y);\n                while (nxtx[x][y] != -1) {\n                    int nx = nxtx[x][y], ny = nxty[x][y];\n                    do_swap(x, y, nx, ny);\n                    x = nx; y = ny;\n                    if ((int)ops.size() > 10000) {\n                        return Candidate{ops, count_violations(a)};\n                    }\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\nCandidate solve_value_order(const Board& init, bool upward, ValueParams prm, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    ValueOrderSolver solver(b, prm, upward);\n    Candidate c = solver.run();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nCandidate solve_builder_top(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_topdown();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nCandidate solve_builder_bottom(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_bottomup();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    prepare_globals();\n\n    Board init{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n        }\n    }\n\n    vector<Candidate> cands;\n    cands.reserve(64);\n\n    // Baseline.\n    cands.push_back(Candidate{{}, count_violations(init)});\n\n    // Stronger value-order parameter family.\n    vector<ValueParams> params = {\n        {1000000000LL, 0,  0,  -1}, // pure shortest path\n        {800LL,        1,  0,  -1},\n        {600LL,        1,  0,  -1},\n        {450LL,        1,  0,  -1},\n        {600LL,        1, 16,  -1},\n        {450LL,        1, 16,  -1},\n        {320LL,        1, 20,  -1},\n        {260LL,        1, 24,  -1},\n        {450LL,        1, 16,   0},\n        {450LL,        1, 16,   1},\n        {320LL,        1, 20,   2},\n        {320LL,        1, 20,   3},\n    };\n\n    for (const auto& prm : params) {\n        cands.push_back(solve_value_order(init, true,  prm, false));\n        cands.push_back(solve_value_order(init, true,  prm, true));\n        cands.push_back(solve_value_order(init, false, prm, false));\n        cands.push_back(solve_value_order(init, false, prm, true));\n    }\n\n    // Keep previous constructive family as fallback diversity.\n    cands.push_back(solve_builder_top(init, false));\n    cands.push_back(solve_builder_top(init, true));\n    cands.push_back(solve_builder_bottom(init, false));\n    cands.push_back(solve_builder_bottom(init, true));\n\n    Candidate best = normalize_candidate(init, std::move(cands[0]));\n    for (size_t i = 1; i < cands.size(); ++i) {\n        Candidate cur = normalize_candidate(init, std::move(cands[i]));\n        if (better_candidate(cur, best)) best = std::move(cur);\n    }\n\n    if ((int)best.ops.size() > 10000) {\n        best.ops.clear();\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& op : best.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick() : n(0) {}\n    Fenwick(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int r) const { // [0, r)\n        int s = 0;\n        for (; r > 0; r -= r & -r) s += bit[r];\n        return s;\n    }\n    int total() const { return sumPrefix(n); }\n};\n\nstruct Strategy {\n    int hmode; // peel-order heuristic\n    int smode; // choose mode\n};\n\nstruct PeelInfo {\n    array<int, 81> pos;\n    vector<int> safe0;\n};\n\nclass Solver {\n    static constexpr int V = 81;\n    int D, N, M;\n    int root;\n    array<char, V> obstacle{};\n    array<vector<int>, V> adj;\n    array<int, V> dist0{};\n    vector<int> cells; // non-obstacle, non-root cells\n\n    Strategy best_strategy{0, 0};\n    array<int, V> label{};\n\n    int id(int i, int j) const { return i * D + j; }\n\n    void build_adj() {\n        for (int v = 0; v < V; ++v) adj[v].clear();\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int u = id(i, j);\n                if (obstacle[u]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir], nj = j + dj[dir];\n                    if (ni < 0 || ni >= D || nj < 0 || nj >= D) continue;\n                    int v = id(ni, nj);\n                    if (obstacle[v]) continue;\n                    adj[u].push_back(v);\n                }\n            }\n        }\n    }\n\n    void bfs_dist(const array<char, V>& active, array<int, V>& dist) const {\n        dist.fill(-1);\n        queue<int> q;\n        if (!active[root]) return;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (!active[v] || dist[v] != -1) continue;\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n\n    void dfs_art(\n        int u, int p,\n        const array<char, V>& active,\n        array<int, V>& ord,\n        array<int, V>& low,\n        array<char, V>& arti,\n        int& timer\n    ) const {\n        ord[u] = low[u] = timer++;\n        int child = 0;\n        for (int v : adj[u]) {\n            if (!active[v]) continue;\n            if (ord[v] == -1) {\n                ++child;\n                dfs_art(v, u, active, ord, low, arti, timer);\n                low[u] = min(low[u], low[v]);\n                if (p != -1 && low[v] >= ord[u]) arti[u] = 1;\n            } else if (v != p) {\n                low[u] = min(low[u], ord[v]);\n            }\n        }\n        if (p == -1 && child > 1) arti[u] = 1;\n    }\n\n    void compute_articulation(const array<char, V>& active, array<char, V>& arti) const {\n        arti.fill(0);\n        array<int, V> ord, low;\n        ord.fill(-1);\n        low.fill(-1);\n        int timer = 0;\n        if (active[root]) dfs_art(root, -1, active, ord, low, arti, timer);\n    }\n\n    array<int, 4> make_key(\n        int v,\n        const array<int, V>& dist,\n        const array<int, V>& deg,\n        int hmode\n    ) const {\n        // Bigger key => removed earlier in canonical peel\n        if (hmode == 0) {\n            // Dynamic distance first\n            return {dist[v], -deg[v], dist0[v], -v};\n        } else if (hmode == 1) {\n            // Static distance first\n            return {dist0[v], -deg[v], dist[v], -v};\n        } else {\n            // Mixed\n            return {2 * dist[v] + dist0[v], -deg[v], dist[v], -v};\n        }\n    }\n\n    PeelInfo peel_info(const array<char, V>& occupied, const Strategy& st) const {\n        PeelInfo info;\n        info.pos.fill(-1);\n        info.safe0.clear();\n\n        array<char, V> active{};\n        active.fill(0);\n        active[root] = 1;\n        int rem = 0;\n        for (int v : cells) {\n            if (!occupied[v]) {\n                active[v] = 1;\n                ++rem;\n            }\n        }\n\n        for (int step = 0; step < rem; ++step) {\n            array<int, V> dist;\n            bfs_dist(active, dist);\n\n            array<char, V> arti;\n            compute_articulation(active, arti);\n\n            array<int, V> deg{};\n            deg.fill(0);\n            for (int u = 0; u < V; ++u) {\n                if (!active[u]) continue;\n                for (int v : adj[u]) if (active[v]) ++deg[u];\n            }\n\n            vector<int> safe;\n            int best = -1;\n            array<int, 4> bestKey{};\n\n            for (int v : cells) {\n                if (!active[v]) continue;\n                if (dist[v] == -1) continue; // should not happen\n                if (arti[v]) continue;\n                safe.push_back(v);\n                auto key = make_key(v, dist, deg, st.hmode);\n                if (best == -1 || key > bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n\n            if (step == 0) info.safe0 = safe;\n\n            if (best == -1) {\n                // Fallback; theoretically unnecessary\n                for (int v : cells) {\n                    if (active[v] && dist[v] != -1) {\n                        best = v;\n                        break;\n                    }\n                }\n                if (step == 0 && info.safe0.empty() && best != -1) {\n                    info.safe0.push_back(best);\n                }\n            }\n\n            if (best == -1) break;\n            info.pos[best] = step;\n            active[best] = 0;\n        }\n\n        return info;\n    }\n\n    int choose_cell(const array<char, V>& occupied, const Fenwick& unseen, int t, const Strategy& st) const {\n        int m = unseen.total();\n        int r = unseen.sumPrefix(t); // current label rank among unseen\n\n        PeelInfo info = peel_info(occupied, st);\n        vector<int> safe = info.safe0;\n\n        if (safe.empty()) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) if (!occupied[v]) return v;\n            return cells.front();\n        }\n\n        if (st.smode == 0) {\n            // Quantile among currently legal choices\n            sort(safe.begin(), safe.end(), [&](int a, int b) {\n                if (info.pos[a] != info.pos[b]) return info.pos[a] > info.pos[b];\n                return a < b;\n            });\n            int idx = (int)((long long)r * (int)safe.size() / m);\n            if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n            return safe[idx];\n        } else {\n            // Closest to absolute target position in canonical peel\n            int target = m - 1 - r; // large => early output\n            int best = -1;\n            pair<int, int> bestPair{INT_MAX, INT_MAX};\n            for (int v : safe) {\n                int d = abs(info.pos[v] - target);\n                int tie = (target * 2 >= m - 1) ? -info.pos[v] : info.pos[v];\n                pair<int, int> cur{d, tie};\n                if (best == -1 || cur < bestPair) {\n                    best = v;\n                    bestPair = cur;\n                }\n            }\n            return best;\n        }\n    }\n\n    int best_reachable_smallest(const array<char, V>& occ, const array<int, V>& lbl) const {\n        array<char, V> vis{};\n        vis.fill(0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n\n        int best = -1;\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (occ[v]) {\n                    if (best == -1 || lbl[v] < lbl[best]) best = v;\n                } else {\n                    if (!vis[v]) {\n                        vis[v] = 1;\n                        q.push(v);\n                    }\n                }\n            }\n        }\n\n        if (best == -1) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) {\n                if (occ[v] && (best == -1 || lbl[v] < lbl[best])) best = v;\n            }\n        }\n        return best;\n    }\n\n    long long simulate(const Strategy& st, const vector<int>& perm) const {\n        array<char, V> occ{};\n        occ.fill(0);\n        array<int, V> lbl;\n        lbl.fill(-1);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int x : perm) {\n            int c = choose_cell(occ, unseen, x, st);\n            occ[c] = 1;\n            lbl[c] = x;\n            unseen.add(x, -1);\n        }\n\n        array<char, V> curOcc = occ;\n        vector<int> out;\n        out.reserve(M);\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, lbl);\n            out.push_back(lbl[c]);\n            curOcc[c] = 0;\n        }\n\n        long long inv = 0;\n        for (int i = 0; i < M; ++i) {\n            for (int j = i + 1; j < M; ++j) {\n                if (out[i] > out[j]) ++inv;\n            }\n        }\n        return inv;\n    }\n\n    void train_best_strategy() {\n        vector<Strategy> cand = {\n            {0, 0}, {0, 1},\n            {1, 0}, {1, 1},\n            {2, 0}, {2, 1}\n        };\n\n        uint64_t seed = 1469598103934665603ULL;\n        seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n        for (int v = 0; v < V; ++v) {\n            if (obstacle[v]) {\n                seed ^= (uint64_t)(v + 1);\n                seed *= 1099511628211ULL;\n            }\n        }\n        mt19937_64 rng(seed);\n\n        const int TRAIN_ITERS = 4;\n        vector<vector<int>> perms(TRAIN_ITERS, vector<int>(M));\n        for (int it = 0; it < TRAIN_ITERS; ++it) {\n            iota(perms[it].begin(), perms[it].end(), 0);\n            shuffle(perms[it].begin(), perms[it].end(), rng);\n        }\n\n        long long bestScore = (1LL << 62);\n        for (const auto& st : cand) {\n            long long sumInv = 0;\n            for (int it = 0; it < TRAIN_ITERS; ++it) {\n                sumInv += simulate(st, perms[it]);\n            }\n            if (sumInv < bestScore) {\n                bestScore = sumInv;\n                best_strategy = st;\n            }\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> D >> N;\n        root = id(0, (D - 1) / 2);\n\n        obstacle.fill(0);\n        label.fill(-1);\n\n        for (int k = 0; k < N; ++k) {\n            int i, j;\n            cin >> i >> j;\n            obstacle[id(i, j)] = 1;\n        }\n\n        build_adj();\n\n        cells.clear();\n        for (int v = 0; v < V; ++v) {\n            if (!obstacle[v] && v != root) cells.push_back(v);\n        }\n        M = (int)cells.size();\n\n        // Original distances\n        array<char, V> active{};\n        active.fill(0);\n        for (int v = 0; v < V; ++v) if (!obstacle[v]) active[v] = 1;\n        bfs_dist(active, dist0);\n\n        train_best_strategy();\n\n        array<char, V> occupied{};\n        occupied.fill(0);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int d = 0; d < M; ++d) {\n            int t;\n            cin >> t;\n\n            int c = choose_cell(occupied, unseen, t, best_strategy);\n            occupied[c] = 1;\n            label[c] = t;\n            unseen.add(t, -1);\n\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            cout.flush();\n        }\n\n        array<char, V> curOcc = occupied;\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, label);\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            curOcc[c] = 0;\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXV = 2500;\nstatic constexpr int MAXC = 101;\n\nint n, m;\nbool origAdj[MAXC][MAXC];\nint distColor[MAXC];\nint degColor[MAXC];\nvector<vector<int>> depthGroups;\n\nstruct Board {\n    int h = 0, w = 0;\n    array<unsigned char, MAXV> a{};\n    int nonzero = 0;\n    long long distsum = 0;\n};\n\ninline bool better_board(const Board& x, const Board& y) {\n    if (x.nonzero != y.nonzero) return x.nonzero < y.nonzero;\n    if (x.distsum != y.distsum) return x.distsum < y.distsum;\n    return x.h * x.w < y.h * y.w;\n}\n\ninline bool not_worse_board(const Board& x, const Board& y) {\n    return !better_board(y, x);\n}\n\nuint64_t hash_board(const Board& b) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)b.h + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    h ^= (uint64_t)b.w + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    int V = b.h * b.w;\n    for (int i = 0; i < V; ++i) {\n        h ^= (uint64_t)(b.a[i] + 1) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    }\n    return h;\n}\n\nvoid compute_stats(Board& b) {\n    b.nonzero = 0;\n    b.distsum = 0;\n    int V = b.h * b.w;\n    for (int i = 0; i < V; ++i) {\n        int c = b.a[i];\n        if (c != 0) ++b.nonzero;\n        b.distsum += distColor[c];\n    }\n}\n\ninline bool row_all_zero(const Board& b, int r) {\n    int base = r * b.w;\n    for (int j = 0; j < b.w; ++j) {\n        if (b.a[base + j] != 0) return false;\n    }\n    return true;\n}\n\ninline bool col_all_zero(const Board& b, int c) {\n    for (int i = 0; i < b.h; ++i) {\n        if (b.a[i * b.w + c] != 0) return false;\n    }\n    return true;\n}\n\nBoard delete_row_board(const Board& b, int r, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h - 1;\n    nb.w = b.w;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r) continue;\n        memcpy(&nb.a[p], &b.a[i * b.w], b.w * sizeof(unsigned char));\n        p += b.w;\n    }\n    return nb;\n}\n\nBoard delete_col_board(const Board& b, int c, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h;\n    nb.w = b.w - 1;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nvoid crop_zero_border(Board& b) {\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        while (b.h > 1 && row_all_zero(b, 0)) {\n            b = delete_row_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.h > 1 && row_all_zero(b, b.h - 1)) {\n            b = delete_row_board(b, b.h - 1, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, 0)) {\n            b = delete_col_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, b.w - 1)) {\n            b = delete_col_board(b, b.w - 1, 0, 0);\n            changed = true;\n        }\n    }\n}\n\nint sparse_score(const Board& b) {\n    int r1 = 1e9, r2 = 1e9;\n    for (int i = 0; i < b.h; ++i) {\n        int cnt = 0;\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) cnt += (b.a[base + j] != 0);\n        if (cnt < r1) { r2 = r1; r1 = cnt; }\n        else if (cnt < r2) r2 = cnt;\n    }\n    int c1 = 1e9, c2 = 1e9;\n    for (int j = 0; j < b.w; ++j) {\n        int cnt = 0;\n        for (int i = 0; i < b.h; ++i) cnt += (b.a[i * b.w + j] != 0);\n        if (cnt < c1) { c2 = c1; c1 = cnt; }\n        else if (cnt < c2) c2 = cnt;\n    }\n    if (r1 == 1e9) r1 = 0;\n    if (r2 == 1e9) r2 = r1;\n    if (c1 == 1e9) c1 = 0;\n    if (c2 == 1e9) c2 = c1;\n    return r1 + r2 + c1 + c2;\n}\n\nbool is_legal(const Board& b) {\n    static int cnt[MAXC], firstPos[MAXC];\n    static bool adj[MAXC][MAXC];\n    static int vis[MAXV];\n    static int q[MAXV];\n    static int vis0[(MAXN + 2) * (MAXN + 2)];\n    static int q0[(MAXN + 2) * (MAXN + 2)];\n\n    memset(cnt, 0, sizeof(cnt));\n    memset(firstPos, -1, sizeof(firstPos));\n    memset(adj, 0, sizeof(adj));\n\n    int h = b.h, w = b.w;\n    int zeroCnt = 0;\n\n    for (int i = 0; i < h; ++i) {\n        int base = i * w;\n        for (int j = 0; j < w; ++j) {\n            int idx = base + j;\n            int c = b.a[idx];\n            if (c == 0) {\n                ++zeroCnt;\n            } else {\n                ++cnt[c];\n                if (firstPos[c] == -1) firstPos[c] = idx;\n            }\n\n            if ((i == 0 || i == h - 1 || j == 0 || j == w - 1) && c != 0) {\n                adj[c][0] = adj[0][c] = true;\n            }\n\n            if (i + 1 < h) {\n                int d = b.a[idx + w];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n            if (j + 1 < w) {\n                int d = b.a[idx + 1];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n        }\n    }\n\n    for (int c = 1; c <= m; ++c) {\n        if (cnt[c] == 0) return false;\n    }\n\n    for (int c = 0; c <= m; ++c) {\n        for (int d = 0; d <= m; ++d) {\n            if (adj[c][d] != origAdj[c][d]) return false;\n        }\n    }\n\n    memset(vis, 0, sizeof(vis));\n    int stamp = 1;\n\n    for (int color = 1; color <= m; ++color) {\n        if (cnt[color] <= 1) {\n            ++stamp;\n            continue;\n        }\n\n        int start = firstPos[color];\n        int ql = 0, qr = 0;\n        q[qr++] = start;\n        vis[start] = stamp;\n        int seen = 1;\n\n        while (ql < qr) {\n            int v = q[ql++];\n            int x = v / w, y = v % w;\n\n            if (x > 0) {\n                int to = v - w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (x + 1 < h && seen < cnt[color]) {\n                int to = v + w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (y > 0 && seen < cnt[color]) {\n                int to = v - 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (y + 1 < w && seen < cnt[color]) {\n                int to = v + 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n        }\n\n        if (seen != cnt[color]) return false;\n        ++stamp;\n    }\n\n    if (zeroCnt > 0) {\n        int H = h + 2, W = w + 2;\n        memset(vis0, 0, sizeof(vis0));\n        int ql = 0, qr = 0;\n        q0[qr++] = 0;\n        vis0[0] = 1;\n        int reachedZero = 0;\n\n        auto can_pass = [&](int r, int c) -> bool {\n            if (r < 0 || r >= H || c < 0 || c >= W) return false;\n            int id = r * W + c;\n            if (vis0[id]) return false;\n            if (r == 0 || r == H - 1 || c == 0 || c == W - 1) return true;\n            return b.a[(r - 1) * w + (c - 1)] == 0;\n        };\n\n        while (ql < qr) {\n            int v = q0[ql++];\n            int r = v / W, c = v % W;\n            static const int dr[4] = {-1, 1, 0, 0};\n            static const int dc[4] = {0, 0, -1, 1};\n            for (int k = 0; k < 4; ++k) {\n                int nr = r + dr[k], nc = c + dc[k];\n                if (!can_pass(nr, nc)) continue;\n                int nid = nr * W + nc;\n                vis0[nid] = 1;\n                q0[qr++] = nid;\n                if (1 <= nr && nr <= h && 1 <= nc && nc <= w) ++reachedZero;\n            }\n        }\n\n        if (reachedZero != zeroCnt) return false;\n    }\n\n    return true;\n}\n\nstruct ShrinkCand {\n    Board nb;\n    int sparse = 0;\n};\n\nBoard shrink_pass(Board b, mt19937& rng, Clock::time_point deadline, int randomTopK) {\n    crop_zero_border(b);\n    compute_stats(b);\n\n    while (Clock::now() < deadline) {\n        vector<int> rowNz(b.h, 0), colNz(b.w, 0);\n        vector<long long> rowDist(b.h, 0), colDist(b.w, 0);\n\n        for (int i = 0; i < b.h; ++i) {\n            int base = i * b.w;\n            for (int j = 0; j < b.w; ++j) {\n                int c = b.a[base + j];\n                rowNz[i] += (c != 0);\n                colNz[j] += (c != 0);\n                rowDist[i] += distColor[c];\n                colDist[j] += distColor[c];\n            }\n        }\n\n        vector<ShrinkCand> cands;\n        cands.reserve(b.h + b.w);\n\n        if (b.h > 1) {\n            for (int r = 0; r < b.h; ++r) {\n                if ((r & 7) == 0 && Clock::now() >= deadline) return b;\n                Board nb = delete_row_board(b, r, rowNz[r], rowDist[r]);\n                crop_zero_border(nb);\n                if (is_legal(nb)) {\n                    ShrinkCand sc;\n                    sc.nb = nb;\n                    sc.sparse = sparse_score(nb);\n                    cands.push_back(move(sc));\n                }\n            }\n        }\n\n        if (b.w > 1) {\n            for (int c = 0; c < b.w; ++c) {\n                if ((c & 7) == 0 && Clock::now() >= deadline) return b;\n                Board nb = delete_col_board(b, c, colNz[c], colDist[c]);\n                crop_zero_border(nb);\n                if (is_legal(nb)) {\n                    ShrinkCand sc;\n                    sc.nb = nb;\n                    sc.sparse = sparse_score(nb);\n                    cands.push_back(move(sc));\n                }\n            }\n        }\n\n        if (cands.empty()) break;\n\n        sort(cands.begin(), cands.end(), [](const ShrinkCand& x, const ShrinkCand& y) {\n            if (x.nb.nonzero != y.nb.nonzero) return x.nb.nonzero < y.nb.nonzero;\n            if (x.sparse != y.sparse) return x.sparse < y.sparse;\n            int ax = x.nb.h * x.nb.w, ay = y.nb.h * y.nb.w;\n            if (ax != ay) return ax < ay;\n            if (x.nb.distsum != y.nb.distsum) return x.nb.distsum < y.nb.distsum;\n            return false;\n        });\n\n        int lim = min<int>((int)cands.size(), max(1, randomTopK));\n        int pick = 0;\n        if (lim > 1) {\n            int a = uniform_int_distribution<int>(0, lim - 1)(rng);\n            int b2 = uniform_int_distribution<int>(0, lim - 1)(rng);\n            pick = min(a, b2); // bias toward better ones\n        }\n        b = cands[pick].nb;\n        crop_zero_border(b);\n    }\n\n    return b;\n}\n\nstruct LSState {\n    int h = 0, w = 0, V = 0;\n    array<unsigned char, MAXV> g{};\n    array<int, MAXC> cnt{};\n    int edge[MAXC][MAXC];\n    long long distSum = 0;\n    int nonzero = 0;\n\n    array<array<short, 4>, MAXV> nbr{};\n    array<unsigned char, MAXV> nbrCnt{};\n    array<unsigned char, MAXV> bside{};\n\n    int rowNZ[MAXN]{};\n    int colNZ[MAXN]{};\n};\n\nLSState build_state(const Board& b) {\n    LSState st;\n    st.h = b.h;\n    st.w = b.w;\n    st.V = b.h * b.w;\n    st.cnt.fill(0);\n    memset(st.edge, 0, sizeof(st.edge));\n    memset(st.rowNZ, 0, sizeof(st.rowNZ));\n    memset(st.colNZ, 0, sizeof(st.colNZ));\n    st.distSum = 0;\n    st.nonzero = 0;\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = b.a[idx];\n        st.g[idx] = b.a[idx];\n        ++st.cnt[c];\n        st.distSum += distColor[c];\n        if (c != 0) {\n            ++st.nonzero;\n            ++st.rowNZ[idx / st.w];\n            ++st.colNZ[idx % st.w];\n        }\n    }\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int i = idx / st.w, j = idx % st.w;\n        int k = 0;\n        if (i > 0) st.nbr[idx][k++] = idx - st.w;\n        if (i + 1 < st.h) st.nbr[idx][k++] = idx + st.w;\n        if (j > 0) st.nbr[idx][k++] = idx - 1;\n        if (j + 1 < st.w) st.nbr[idx][k++] = idx + 1;\n        st.nbrCnt[idx] = (unsigned char)k;\n        st.bside[idx] = (unsigned char)((i == 0) + (i == st.h - 1) + (j == 0) + (j == st.w - 1));\n    }\n\n    auto add_edge = [&](int a, int b, int delta) {\n        if (a == b) return;\n        st.edge[a][b] += delta;\n        st.edge[b][a] += delta;\n    };\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = st.g[idx];\n        int i = idx / st.w, j = idx % st.w;\n        if (i == 0) add_edge(c, 0, 1);\n        if (i == st.h - 1) add_edge(c, 0, 1);\n        if (j == 0) add_edge(c, 0, 1);\n        if (j == st.w - 1) add_edge(c, 0, 1);\n        if (i + 1 < st.h) add_edge(c, st.g[idx + st.w], 1);\n        if (j + 1 < st.w) add_edge(c, st.g[idx + 1], 1);\n    }\n\n    return st;\n}\n\nstatic int conn_vis[MAXV];\nstatic int conn_stamp = 1;\n\nbool connected_after_remove(const LSState& st, int color, int remIdx, int need, int startIdx) {\n    ++conn_stamp;\n    if (conn_stamp == INT_MAX) {\n        memset(conn_vis, 0, sizeof(conn_vis));\n        conn_stamp = 1;\n    }\n\n    static int q[MAXV];\n    int ql = 0, qr = 0;\n    q[qr++] = startIdx;\n    conn_vis[startIdx] = conn_stamp;\n    int seen = 1;\n\n    while (ql < qr) {\n        int v = q[ql++];\n        int deg = st.nbrCnt[v];\n        for (int k = 0; k < deg; ++k) {\n            int to = st.nbr[v][k];\n            if (to == remIdx) continue;\n            if (st.g[to] != color) continue;\n            if (conn_vis[to] == conn_stamp) continue;\n            conn_vis[to] = conn_stamp;\n            q[qr++] = to;\n            if (++seen == need) return true;\n        }\n    }\n    return seen == need;\n}\n\ninline bool can_to_zero(const LSState& st, int idx) {\n    if (st.bside[idx] > 0) return true;\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        if (st.g[st.nbr[idx][k]] == 0) return true;\n    }\n    return false;\n}\n\nbool try_move(LSState& st, int idx, int t) {\n    int c = st.g[idx];\n    if (c == 0 || c == t) return false;\n    if (st.cnt[c] <= 1) return false;\n\n    int sameNbr = 0;\n    int startIdx = -1;\n    bool targetConnected = false;\n\n    if (t == 0 && st.bside[idx] > 0) targetConnected = true;\n\n    int pa[12], pb[12], pd[12];\n    int pnum = 0;\n\n    auto add_change = [&](int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < pnum; ++i) {\n            if (pa[i] == a && pb[i] == b) {\n                pd[i] += d;\n                return;\n            }\n        }\n        pa[pnum] = a;\n        pb[pnum] = b;\n        pd[pnum] = d;\n        ++pnum;\n    };\n\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        int to = st.nbr[idx][k];\n        int d = st.g[to];\n\n        if (d == c) {\n            ++sameNbr;\n            startIdx = to;\n        }\n        if (d == t) targetConnected = true;\n        if (t == 0 && d == 0) targetConnected = true;\n\n        if (c != d) add_change(c, d, -1);\n        if (t != d) add_change(t, d, +1);\n    }\n\n    if (st.bside[idx] > 0) {\n        add_change(c, 0, -st.bside[idx]);\n        add_change(t, 0, +st.bside[idx]);\n    }\n\n    if (!targetConnected) return false;\n    if (sameNbr == 0) return false;\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        int nc = st.edge[a][b] + pd[i];\n        if (nc < 0) return false;\n        bool nadj = (nc > 0);\n        if (nadj != origAdj[a][b]) return false;\n    }\n\n    if (sameNbr >= 2) {\n        if (!connected_after_remove(st, c, idx, st.cnt[c] - 1, startIdx)) return false;\n    }\n\n    st.g[idx] = (unsigned char)t;\n    --st.cnt[c];\n    ++st.cnt[t];\n    st.distSum += (long long)distColor[t] - distColor[c];\n\n    if (t == 0) {\n        --st.nonzero;\n        --st.rowNZ[idx / st.w];\n        --st.colNZ[idx % st.w];\n    }\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        st.edge[a][b] += pd[i];\n        st.edge[b][a] += pd[i];\n    }\n\n    return true;\n}\n\narray<int, MAXC> make_key(const LSState& st, mt19937& rng) {\n    array<int, MAXC> key{};\n    key.fill(0);\n    key[0] = 0;\n\n    for (int d = 1; d < (int)depthGroups.size(); ++d) {\n        vector<int> v = depthGroups[d];\n        shuffle(v.begin(), v.end(), rng);\n        stable_sort(v.begin(), v.end(), [&](int a, int b) {\n            if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n            if (degColor[a] != degColor[b]) return degColor[a] > degColor[b];\n            return a < b;\n        });\n        for (int i = 0; i < (int)v.size(); ++i) {\n            key[v[i]] = d * 1000 + (i + 1);\n        }\n    }\n    return key;\n}\n\nbool attempt_best_move(LSState& st, int idx, const array<int, MAXC>& key) {\n    int c = st.g[idx];\n    if (c == 0) return false;\n\n    int cand[5];\n    int ccnt = 0;\n\n    auto add_cand = [&](int x) {\n        if (x == c) return;\n        if (x != 0 && key[x] >= key[c]) return;\n        for (int i = 0; i < ccnt; ++i) {\n            if (cand[i] == x) return;\n        }\n        cand[ccnt++] = x;\n    };\n\n    if (can_to_zero(st, idx)) add_cand(0);\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) add_cand(st.g[st.nbr[idx][k]]);\n\n    sort(cand, cand + ccnt, [&](int a, int b) {\n        if (a == 0 || b == 0) return a == 0;\n        if (key[a] != key[b]) return key[a] < key[b];\n        if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < ccnt; ++i) {\n        if (try_move(st, idx, cand[i])) return true;\n    }\n    return false;\n}\n\nbool global_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n    vector<int> ord(st.V);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n\n    stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int ca = st.g[a], cb = st.g[b];\n        if (ca == 0 || cb == 0) return ca != 0;\n\n        if (key[ca] != key[cb]) return key[ca] > key[cb];\n\n        int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n        int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n        if (ma != mb) return ma < mb;\n\n        int sa = st.rowNZ[a / st.w] + st.colNZ[a % st.w];\n        int sb = st.rowNZ[b / st.w] + st.colNZ[b % st.w];\n        return sa < sb;\n    });\n\n    bool moved = false;\n    for (int it = 0; it < st.V; ++it) {\n        if ((it & 255) == 0 && Clock::now() >= deadline) break;\n        int idx = ord[it];\n        if (attempt_best_move(st, idx, key)) moved = true;\n    }\n    return moved;\n}\n\nbool line_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n\n    vector<pair<int, int>> lines;\n    lines.reserve(st.h + st.w);\n    for (int i = 0; i < st.h; ++i) if (st.rowNZ[i] > 0) lines.push_back({st.rowNZ[i], i});\n    for (int j = 0; j < st.w; ++j) if (st.colNZ[j] > 0) lines.push_back({st.colNZ[j], st.h + j});\n\n    if (lines.empty()) return false;\n\n    shuffle(lines.begin(), lines.end(), rng);\n    stable_sort(lines.begin(), lines.end(), [](const auto& a, const auto& b) {\n        return a.first < b.first;\n    });\n\n    int L = min<int>((int)lines.size(), 8);\n    bool moved = false;\n\n    for (int li = 0; li < L; ++li) {\n        if ((li & 3) == 0 && Clock::now() >= deadline) break;\n\n        int code = lines[li].second;\n        vector<int> cells;\n\n        if (code < st.h) {\n            int r = code;\n            cells.reserve(st.rowNZ[r]);\n            for (int j = 0; j < st.w; ++j) {\n                int idx = r * st.w + j;\n                if (st.g[idx] != 0) cells.push_back(idx);\n            }\n        } else {\n            int c = code - st.h;\n            cells.reserve(st.colNZ[c]);\n            for (int i = 0; i < st.h; ++i) {\n                int idx = i * st.w + c;\n                if (st.g[idx] != 0) cells.push_back(idx);\n            }\n        }\n\n        shuffle(cells.begin(), cells.end(), rng);\n        stable_sort(cells.begin(), cells.end(), [&](int a, int b) {\n            bool za = can_to_zero(st, a), zb = can_to_zero(st, b);\n            if (za != zb) return za > zb;\n\n            int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n            int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n            if (ma != mb) return ma < mb;\n\n            int ka = key[st.g[a]], kb = key[st.g[b]];\n            if (ka != kb) return ka > kb;\n\n            int sa = st.rowNZ[a / st.w] + st.colNZ[a % st.w];\n            int sb = st.rowNZ[b / st.w] + st.colNZ[b % st.w];\n            return sa < sb;\n        });\n\n        for (int idx : cells) {\n            if (Clock::now() >= deadline) break;\n            if (attempt_best_move(st, idx, key)) moved = true;\n        }\n    }\n\n    return moved;\n}\n\nvoid optimize(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    int stagnation = 0;\n    int phase = 0;\n\n    while (Clock::now() < deadline && stagnation < 5) {\n        bool moved = false;\n        if (phase % 3 == 1) {\n            moved = line_round(st, rng, deadline);\n        } else {\n            moved = global_round(st, rng, deadline);\n        }\n        if (!moved && Clock::now() < deadline) {\n            moved = line_round(st, rng, deadline);\n        }\n        if (moved) stagnation = 0;\n        else ++stagnation;\n        ++phase;\n    }\n}\n\nBoard state_to_board(const LSState& st) {\n    Board b;\n    b.h = st.h;\n    b.w = st.w;\n    b.nonzero = st.nonzero;\n    b.distsum = st.distSum;\n    for (int i = 0; i < st.V; ++i) b.a[i] = st.g[i];\n    return b;\n}\n\nBoard shave_pass(Board b, mt19937& rng, Clock::time_point deadline) {\n    crop_zero_border(b);\n    compute_stats(b);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(16);\n    seen.insert(hash_board(b));\n\n    int stagnation = 0;\n\n    while (Clock::now() < deadline && stagnation < 3) {\n        auto now = Clock::now();\n        auto rem_ms = chrono::duration_cast<chrono::milliseconds>(deadline - now).count();\n        int slice = (int)max<long long>(20, rem_ms / 2);\n        auto inner_deadline = min(deadline, now + chrono::milliseconds(slice));\n\n        LSState st = build_state(b);\n        optimize(st, rng, inner_deadline);\n        Board nb = state_to_board(st);\n        crop_zero_border(nb);\n        compute_stats(nb);\n\n        uint64_t h = hash_board(nb);\n        if ((better_board(nb, b) || (not_worse_board(nb, b) && !seen.count(h)))) {\n            b = nb;\n            seen.insert(h);\n            stagnation = 0;\n        } else {\n            ++stagnation;\n        }\n    }\n\n    return b;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n >> m;\n\n    Board original;\n    original.h = n;\n    original.w = n;\n\n    uint64_t seed64 = 1234567891234567ULL;\n    for (int i = 0; i < n * n; ++i) {\n        int x;\n        cin >> x;\n        original.a[i] = (unsigned char)x;\n        seed64 ^= (uint64_t)(x + 1) + 0x9e3779b97f4a7c15ULL + (seed64 << 6) + (seed64 >> 2);\n    }\n\n    memset(origAdj, 0, sizeof(origAdj));\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int idx = i * n + j;\n            int c = original.a[idx];\n\n            if (i == 0 || i == n - 1 || j == 0 || j == n - 1) {\n                origAdj[c][0] = origAdj[0][c] = true;\n            }\n            if (i + 1 < n) {\n                int d = original.a[idx + n];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n            if (j + 1 < n) {\n                int d = original.a[idx + 1];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n        }\n    }\n\n    const int INF = 1e9;\n    for (int i = 0; i <= m; ++i) distColor[i] = INF;\n    queue<int> q;\n    distColor[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (int to = 0; to <= m; ++to) {\n            if (!origAdj[v][to]) continue;\n            if (distColor[to] != INF) continue;\n            distColor[to] = distColor[v] + 1;\n            q.push(to);\n        }\n    }\n\n    for (int i = 0; i <= m; ++i) {\n        int dg = 0;\n        for (int j = 0; j <= m; ++j) if (origAdj[i][j]) ++dg;\n        degColor[i] = dg;\n    }\n\n    int maxDepth = 0;\n    for (int c = 1; c <= m; ++c) maxDepth = max(maxDepth, distColor[c]);\n    depthGroups.assign(maxDepth + 1, {});\n    for (int c = 1; c <= m; ++c) depthGroups[distColor[c]].push_back(c);\n\n    compute_stats(original);\n\n    mt19937 rng((uint32_t)(seed64 ^ (seed64 >> 32)));\n\n    auto start = Clock::now();\n    auto deadline = start + chrono::milliseconds(1930);\n\n    auto sub_deadline = [&](int ms) -> Clock::time_point {\n        return min(deadline, Clock::now() + chrono::milliseconds(ms));\n    };\n\n    Board best = original;\n    Board cur = original;\n\n    // Initial diversified runs.\n    vector<int> initK = {1, 2, 3, 5};\n    for (int k : initK) {\n        if (Clock::now() >= deadline) break;\n        Board cand = shrink_pass(original, rng, sub_deadline(120), k);\n        cand = shave_pass(cand, rng, sub_deadline(140));\n        cand = shrink_pass(cand, rng, sub_deadline(80), k + 1);\n        if (better_board(cand, best)) best = cand;\n    }\n    cur = best;\n\n    int iter = 0;\n    while (Clock::now() < deadline) {\n        Board seed;\n        if (iter % 5 == 0) seed = original;\n        else if (iter % 5 == 1 || iter % 5 == 2) seed = best;\n        else seed = cur;\n\n        Board cand = seed;\n        int k1 = 1 + (rng() % 6);\n        int k2 = 1 + (rng() % 6);\n\n        if (iter % 2 == 0) {\n            cand = shrink_pass(cand, rng, sub_deadline(70), k1);\n            cand = shave_pass(cand, rng, sub_deadline(90));\n            cand = shrink_pass(cand, rng, sub_deadline(60), k2);\n        } else {\n            cand = shave_pass(cand, rng, sub_deadline(80));\n            cand = shrink_pass(cand, rng, sub_deadline(80), k1);\n            cand = shave_pass(cand, rng, sub_deadline(50));\n        }\n\n        if (better_board(cand, best)) best = cand;\n        if (better_board(cand, cur) || iter % 3 == 0) cur = cand;\n        else cur = best;\n\n        ++iter;\n    }\n\n    crop_zero_border(best);\n    compute_stats(best);\n\n    vector<vector<int>> out(n, vector<int>(n, 0));\n    for (int i = 0; i < best.h; ++i) {\n        for (int j = 0; j < best.w; ++j) {\n            out[i][j] = best.a[i * best.w + j];\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << out[i][j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n\n    vector<int> cost_ins;\n    vector<vector<signed char>> itemMemo;\n    vector<vector<signed char>> blockMemo;\n\n    vector<vector<int>> blocks;\n    vector<vector<int>> bins;\n\n    vector<int> order_est;\n    vector<int> rank_pos;\n    vector<double> pweight;\n    vector<double> est_load;\n    vector<double> harm;\n\n    int M = 1;\n    int baseSize = 1;\n    int remBlocks = 0;\n    int iterBound = 0;\n    int reserve_balance = 0;\n\n    static signed char enc(char c) {\n        if (c == '>') return 1;\n        if (c == '<') return -1;\n        return 2;\n    }\n    static char dec(signed char v) {\n        if (v == 1) return '>';\n        if (v == -1) return '<';\n        return '=';\n    }\n    static char rev(char c) {\n        if (c == '>') return '<';\n        if (c == '<') return '>';\n        return '=';\n    }\n\n    int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 0, y = 1;\n        while (y < x) y <<= 1, ++p;\n        return p;\n    }\n\n    char ask_sets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) exit(0);\n\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        ++used;\n        return s[0];\n    }\n\n    char cmp_item(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = itemMemo[a][b];\n        if (m != 0) return dec(m);\n        char s = ask_sets(vector<int>{a}, vector<int>{b});\n        itemMemo[a][b] = enc(s);\n        itemMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    // Compare blocks by the sum of their first baseSize items.\n    char cmp_block(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = blockMemo[a][b];\n        if (m != 0) return dec(m);\n\n        vector<int> L, R;\n        L.reserve(baseSize);\n        R.reserve(baseSize);\n        for (int i = 0; i < baseSize; ++i) L.push_back(blocks[a][i]);\n        for (int i = 0; i < baseSize; ++i) R.push_back(blocks[b][i]);\n\n        char s = ask_sets(L, R);\n        blockMemo[a][b] = enc(s);\n        blockMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    void precompute_costs() {\n        cost_ins.assign(N + 1, 0);\n        for (int n = 1; n <= N; ++n) {\n            cost_ins[n] = cost_ins[n - 1] + ceil_log2_int(n);\n        }\n\n        harm.assign(N + 1, 0.0);\n        for (int i = 1; i <= N; ++i) harm[i] = harm[i - 1] + 1.0 / i;\n    }\n\n    int scheme_cost(int m) {\n        int base = N / m;\n        int rem = N % m;\n        long long c = 1LL * rem * cost_ins[base + 1]\n                    + 1LL * (m - rem) * cost_ins[base]\n                    + cost_ins[m];\n        return (int)c;\n    }\n\n    void choose_scheme() {\n        iterBound = 2 * (D - 1) + 6 + 2 * ceil_log2_int(N);\n        reserve_balance = min(Q, 2 * iterBound);\n\n        double bestScore = -1e100;\n        int bestM = 1;\n\n        for (int m = 1; m <= N; ++m) {\n            int c = scheme_cost(m);\n            if (c > Q) continue;\n            int extra = max(0, Q - c - reserve_balance);\n            double place_cnt = 0.0;\n            if (D > 1) place_cnt = min<double>(N - D, extra / double(D - 1));\n            double score = m + 0.8 * place_cnt;\n            if (score > bestScore + 1e-12 || (abs(score - bestScore) <= 1e-12 && m > bestM)) {\n                bestScore = score;\n                bestM = m;\n            }\n        }\n\n        M = bestM;\n        baseSize = N / M;\n        remBlocks = N % M;\n    }\n\n    vector<int> sort_items_by_weight(const vector<int>& arr) {\n        vector<int> res;\n        res.reserve(arr.size());\n        for (int x : arr) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_item(x, res[mid]); // '>' => x heavier\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, x);\n        }\n        return res;\n    }\n\n    vector<int> sort_block_ids(const vector<int>& ids) {\n        vector<int> res;\n        res.reserve(ids.size());\n        for (int id : ids) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_block(id, res[mid]); // '>' => id heavier\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, id);\n        }\n        return res;\n    }\n\n    // Acklam-style inverse normal CDF approximation\n    double inv_norm(double p) {\n        p = min(1.0 - 1e-12, max(1e-12, p));\n\n        static const double a1 = -3.969683028665376e+01;\n        static const double a2 =  2.209460984245205e+02;\n        static const double a3 = -2.759285104469687e+02;\n        static const double a4 =  1.383577518672690e+02;\n        static const double a5 = -3.066479806614716e+01;\n        static const double a6 =  2.506628277459239e+00;\n\n        static const double b1 = -5.447609879822406e+01;\n        static const double b2 =  1.615858368580409e+02;\n        static const double b3 = -1.556989798598866e+02;\n        static const double b4 =  6.680131188771972e+01;\n        static const double b5 = -1.328068155288572e+01;\n\n        static const double c1 = -7.784894002430293e-03;\n        static const double c2 = -3.223964580411365e-01;\n        static const double c3 = -2.400758277161838e+00;\n        static const double c4 = -2.549732539343734e+00;\n        static const double c5 =  4.374664141464968e+00;\n        static const double c6 =  2.938163982698783e+00;\n\n        static const double d1 =  7.784695709041462e-03;\n        static const double d2 =  3.224671290700398e-01;\n        static const double d3 =  2.445134137142996e+00;\n        static const double d4 =  3.754408661907416e+00;\n\n        const double plow = 0.02425;\n        const double phigh = 1.0 - plow;\n\n        if (p < plow) {\n            double q = sqrt(-2.0 * log(p));\n            return (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /\n                   ((((d1 * q + d2) * q + d3) * q + d4) * q + 1.0);\n        }\n        if (p > phigh) {\n            double q = sqrt(-2.0 * log(1.0 - p));\n            return -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /\n                    ((((d1 * q + d2) * q + d3) * q + d4) * q + 1.0);\n        }\n        double q = p - 0.5;\n        double r = q * q;\n        return (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q /\n               (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1.0);\n    }\n\n    void build_estimated_order() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n\n        blocks.clear();\n        int cur = 0;\n        for (int i = 0; i < M; ++i) {\n            int sz = baseSize + (i < remBlocks ? 1 : 0);\n            vector<int> blk;\n            blk.reserve(sz);\n            for (int j = 0; j < sz; ++j) blk.push_back(items[cur++]);\n            blocks.push_back(sort_items_by_weight(blk));\n        }\n\n        blockMemo.assign(M, vector<signed char>(M, 0));\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        ids = sort_block_ids(ids); // heavy block first\n\n        struct Cand {\n            double key;\n            int block_rank;\n            int pos_in_block;\n            int item;\n        };\n        vector<Cand> cand;\n        cand.reserve(N);\n\n        // Key idea:\n        // - inside a block, use expected order-stat mean\n        // - for block rank, use only a moderate multiplicative adjustment\n        //   so neighboring blocks can interleave naturally.\n        double alpha = 0.85;\n        double denom = sqrt((double)max(1, baseSize));\n\n        for (int br = 0; br < M; ++br) {\n            int id = ids[br];\n            int s = (int)blocks[id].size();\n\n            double p = (M - br - 0.5) / (double)M; // heavy block => larger p\n            double z = inv_norm(p);\n            double scale = exp(alpha * z / denom);\n\n            for (int j = 0; j < s; ++j) {\n                int x = blocks[id][j];\n                double inside = harm[s] - harm[j]; // expected j-th largest in block size s\n                double key = inside * scale;\n                cand.push_back({key, br, j, x});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [&](const Cand& a, const Cand& b) {\n            if (fabs(a.key - b.key) > 1e-12) return a.key > b.key;\n            if (a.block_rank != b.block_rank) return a.block_rank < b.block_rank;\n            if (a.pos_in_block != b.pos_in_block) return a.pos_in_block < b.pos_in_block;\n            return a.item < b.item;\n        });\n\n        order_est.clear();\n        order_est.reserve(N);\n        rank_pos.assign(N, 0);\n        pweight.assign(N, 0.0);\n\n        for (int i = 0; i < N; ++i) {\n            int x = cand[i].item;\n            order_est.push_back(x);\n            rank_pos[x] = i;\n            pweight[x] = harm[N] - harm[i]; // global expected weight from estimated rank\n        }\n    }\n\n    int actual_lightest_bin_simple() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            char s = ask_sets(bins[i], bins[best]);\n            if (s == '<') best = i;\n        }\n        return best;\n    }\n\n    int pseudo_lightest_bin() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            if (est_load[i] < est_load[best] - 1e-12) best = i;\n            else if (abs(est_load[i] - est_load[best]) <= 1e-12) {\n                if (bins[i].size() < bins[best].size()) best = i;\n                else if (bins[i].size() == bins[best].size() && i < best) best = i;\n            }\n        }\n        return best;\n    }\n\n    void insert_sorted_bin(int b, int item) {\n        auto &v = bins[b];\n        int rk = rank_pos[item];\n        auto it = lower_bound(v.begin(), v.end(), rk,\n                              [&](int lhs_item, int rhs_rank) {\n                                  return rank_pos[lhs_item] < rhs_rank;\n                              });\n        v.insert(it, item);\n    }\n\n    void assign_initial() {\n        bins.assign(D, {});\n        est_load.assign(D, 0.0);\n\n        for (int i = 0; i < N; ++i) {\n            int x = order_est[i];\n            int b;\n            if (i < D) {\n                b = i; // ensure all bins nonempty\n            } else if (used + (D - 1) + reserve_balance <= Q) {\n                b = actual_lightest_bin_simple();\n            } else {\n                b = pseudo_lightest_bin();\n            }\n            bins[b].push_back(x); // order_est is descending\n            est_load[b] += pweight[x];\n        }\n    }\n\n    void pseudo_improve() {\n        for (int iter = 0; iter < 2000; ++iter) {\n            int h = 0, l = 0;\n            for (int i = 1; i < D; ++i) {\n                if (est_load[i] > est_load[h]) h = i;\n                if (est_load[i] < est_load[l]) l = i;\n            }\n            if (h == l) break;\n\n            double lh = est_load[h], ll = est_load[l];\n            double bestDelta = -1e-12;\n            int bestType = 0; // 1 move, 2 swap\n            int bestI = -1, bestJ = -1;\n\n            if ((int)bins[h].size() > 1) {\n                for (int i = 0; i < (int)bins[h].size(); ++i) {\n                    int x = bins[h][i];\n                    double w = pweight[x];\n                    double nh = lh - w;\n                    double nl = ll + w;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 1;\n                        bestI = i;\n                    }\n                }\n            }\n\n            for (int i = 0; i < (int)bins[h].size(); ++i) {\n                int x = bins[h][i];\n                double wx = pweight[x];\n                for (int j = 0; j < (int)bins[l].size(); ++j) {\n                    int y = bins[l][j];\n                    double wy = pweight[y];\n                    double nh = lh - wx + wy;\n                    double nl = ll - wy + wx;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 2;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestType == 0) break;\n\n            if (bestType == 1) {\n                int x = bins[h][bestI];\n                bins[h].erase(bins[h].begin() + bestI);\n                insert_sorted_bin(l, x);\n                est_load[h] -= pweight[x];\n                est_load[l] += pweight[x];\n            } else {\n                int x = bins[h][bestI];\n                int y = bins[l][bestJ];\n                bins[h].erase(bins[h].begin() + bestI);\n                bins[l].erase(bins[l].begin() + bestJ);\n                insert_sorted_bin(h, y);\n                insert_sorted_bin(l, x);\n                est_load[h] += pweight[y] - pweight[x];\n                est_load[l] += pweight[x] - pweight[y];\n            }\n        }\n    }\n\n    pair<int, int> actual_extremes() {\n        vector<vector<signed char>> memo(D, vector<signed char>(D, 0));\n        auto cmpBin = [&](int a, int b) -> char {\n            if (a == b) return '=';\n            signed char &m = memo[a][b];\n            if (m != 0) return dec(m);\n            char s = ask_sets(bins[a], bins[b]);\n            memo[a][b] = enc(s);\n            memo[b][a] = enc(rev(s));\n            return s;\n        };\n\n        int hi = 0, lo = 0;\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, hi) == '>') hi = i;\n        }\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, lo) == '<') lo = i;\n        }\n        return {hi, lo};\n    }\n\n    int select_move_candidate(int H, int L) {\n        int m = (int)bins[H].size();\n        if (m <= 1) return -1;\n\n        vector<signed char> memo(m, 0);\n        auto test = [&](int idx) -> char {\n            if (memo[idx] != 0) return dec(memo[idx]);\n            vector<int> left, right;\n            left.reserve(m - 1);\n            right.reserve(bins[L].size() + 1);\n            for (int i = 0; i < m; ++i) if (i != idx) left.push_back(bins[H][i]);\n            for (int x : bins[L]) right.push_back(x);\n            right.push_back(bins[H][idx]);\n            char s = ask_sets(left, right);\n            memo[idx] = enc(s);\n            return s;\n        };\n\n        char s0 = test(0);\n        if (s0 == '>' || s0 == '=') return 0;\n\n        char sl = test(m - 1);\n        if (sl == '=') return m - 1;\n        if (sl == '<') return -1;\n\n        int lo = 0, hi = m - 1; // test(lo) == '<', test(hi) == '>'\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '<') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double v1 = fabs(diff - 2.0 * pweight[bins[H][lo]]);\n        double v2 = fabs(diff - 2.0 * pweight[bins[H][hi]]);\n        return (v2 < v1 ? hi : lo);\n    }\n\n    int select_swap_candidate(int H, int L) {\n        int xidx = (int)bins[H].size() - 1; // lightest in heavy bin\n        int x = bins[H][xidx];\n        int rkx = rank_pos[x];\n\n        int n = (int)bins[L].size();\n        int first = 0;\n        while (first < n && rank_pos[bins[L][first]] < rkx) ++first;\n        if (first == n) return -1;\n\n        vector<signed char> memo(n, 0);\n        auto test = [&](int yidx) -> char {\n            if (memo[yidx] != 0) return dec(memo[yidx]);\n            vector<int> left, right;\n            left.reserve(bins[H].size());\n            right.reserve(bins[L].size());\n            for (int i = 0; i < (int)bins[H].size(); ++i) {\n                if (i != xidx) left.push_back(bins[H][i]);\n            }\n            left.push_back(bins[L][yidx]);\n\n            for (int i = 0; i < (int)bins[L].size(); ++i) {\n                if (i != yidx) right.push_back(bins[L][i]);\n            }\n            right.push_back(x);\n\n            char s = ask_sets(left, right);\n            memo[yidx] = enc(s);\n            return s;\n        };\n\n        char sf = test(first);\n        if (sf == '=') return first;\n        if (sf == '<') return -1;\n\n        char sl = test(n - 1);\n        if (sl == '=') return n - 1;\n        if (sl == '>') return n - 1;\n\n        int lo = first, hi = n - 1; // test(lo) == '>', test(hi) == '<'\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '>') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double wx = pweight[x];\n        double d1 = fabs(diff - 2.0 * (wx - pweight[bins[L][lo]]));\n        double d2 = fabs(diff - 2.0 * (wx - pweight[bins[L][hi]]));\n        return (d2 < d1 ? hi : lo);\n    }\n\n    void apply_move(int H, int L, int idx) {\n        int x = bins[H][idx];\n        bins[H].erase(bins[H].begin() + idx);\n        insert_sorted_bin(L, x);\n        est_load[H] -= pweight[x];\n        est_load[L] += pweight[x];\n    }\n\n    void apply_swap(int H, int L, int yidx) {\n        int xidx = (int)bins[H].size() - 1;\n        int x = bins[H][xidx];\n        int y = bins[L][yidx];\n\n        bins[H].erase(bins[H].begin() + xidx);\n        bins[L].erase(bins[L].begin() + yidx);\n        insert_sorted_bin(H, y);\n        insert_sorted_bin(L, x);\n\n        est_load[H] += pweight[y] - pweight[x];\n        est_load[L] += pweight[x] - pweight[y];\n    }\n\n    void actual_improve() {\n        while (used + iterBound <= Q) {\n            auto [H, L] = actual_extremes();\n            if (H == L) break;\n\n            bool changed = false;\n\n            if ((int)bins[H].size() > 1) {\n                int idx = select_move_candidate(H, L);\n                if (idx != -1) {\n                    apply_move(H, L, idx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) {\n                int yidx = select_swap_candidate(H, L);\n                if (yidx != -1) {\n                    apply_swap(H, L, yidx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void fill_dummy_queries() {\n        while (used < Q) {\n            ask_sets(vector<int>{0}, vector<int>{1});\n        }\n    }\n\n    void output_answer() {\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b]) ans[x] = b;\n        }\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n\n        itemMemo.assign(N, vector<signed char>(N, 0));\n\n        precompute_costs();\n        choose_scheme();\n        build_estimated_order();\n        assign_initial();\n        pseudo_improve();\n        actual_improve();\n        fill_dummy_queries();\n        output_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NMAX = 200;\nstatic constexpr int MMAX = 10;\nstatic constexpr uint8_t REMOVED = 255;\nstatic constexpr int INF = 1e9;\n\nint N, M;\n\nstruct State {\n    uint16_t a[MMAX][NMAX]; // bottom -> top\n    uint8_t h[MMAX];\n    uint8_t st_of[NMAX + 1]; // stack id, or 255 if removed\n    uint8_t pos[NMAX + 1];   // position in stack\n    uint16_t cur;            // next box to remove\n};\n\nstruct Result {\n    int energy = INF;\n    vector<pair<int,int>> ops;\n};\n\nstruct Features {\n    int solo = 0;     // optimistic exact cost if moved blockers disappear\n    int bad = 0;      // non-record-minima from bottom\n    int seg = 0;      // number of forced future expensive moves in solo model\n    int empty = 0;\n};\n\nstruct Node {\n    State st;\n    int g;            // exact energy so far\n    int parent;       // index in nodes, -1 for root\n    uint8_t actionTo; // 1..M, 0 for root\n};\n\nstruct TempChild {\n    State st;\n    int g;\n    int hval;\n    int eval;\n    int parent;\n    uint8_t actionTo;\n    uint16_t cur;\n};\n\nstruct Config {\n    int width;\n    int mode;\n    int greedyDepth;\n};\n\nstatic auto global_start = chrono::steady_clock::now();\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - global_start).count();\n}\n\ninline void pop_all(State& st, vector<pair<int,int>>* ops = nullptr) {\n    while (st.cur <= N) {\n        uint8_t s = st.st_of[st.cur];\n        if (s == REMOVED) {\n            ++st.cur;\n            continue;\n        }\n        if ((int)st.pos[st.cur] + 1 != (int)st.h[s]) break;\n        if (ops) ops->push_back({st.cur, 0});\n        --st.h[s];\n        st.st_of[st.cur] = REMOVED;\n        ++st.cur;\n    }\n}\n\ninline int move_blockers(State& st, int dst) {\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    int start = p + 1;\n    int len = (int)st.h[s] - start;\n    for (int i = start; i < (int)st.h[s]; ++i) {\n        uint16_t x = st.a[s][i];\n        st.a[dst][st.h[dst]] = x;\n        st.st_of[x] = (uint8_t)dst;\n        st.pos[x] = st.h[dst];\n        ++st.h[dst];\n    }\n    st.h[s] = (uint8_t)start;\n    return len;\n}\n\ninline Features calc_features(const State& st) {\n    Features f;\n    int recPos[NMAX];\n\n    for (int i = 0; i < M; ++i) {\n        int h = st.h[i];\n        if (h == 0) {\n            ++f.empty;\n            continue;\n        }\n\n        int rc = 0;\n        int mn = N + 1;\n        for (int j = 0; j < h; ++j) {\n            int x = st.a[i][j];\n            if (x < mn) {\n                mn = x;\n                recPos[rc++] = j;\n            }\n        }\n\n        f.bad += h - rc;\n\n        for (int k = rc - 1; k >= 0; --k) {\n            int end = (k + 1 < rc ? recPos[k + 1] - 1 : h - 1);\n            int above = end - recPos[k];\n            if (above > 0) {\n                f.solo += above + 1;\n                ++f.seg;\n            }\n        }\n    }\n    return f;\n}\n\ninline int estimate(const State& st, int mode) {\n    Features f = calc_features(st);\n    switch (mode) {\n        case 0: return f.solo;\n        case 1: return f.solo + f.bad;\n        case 2: return f.solo + 2 * f.bad;\n        case 3: return f.solo + f.bad + f.seg;\n        default: return f.solo;\n    }\n}\n\nint lookahead_cost(const State& st, int depth, int mode) {\n    if (st.cur > N) return 0;\n    if (depth == 0) return estimate(st, mode);\n\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    if (p + 1 >= (int)st.h[s]) {\n        State nx = st;\n        pop_all(nx, nullptr);\n        return lookahead_cost(nx, depth, mode);\n    }\n\n    int len = (int)st.h[s] - p - 1;\n    int best = INF;\n\n    struct Cand {\n        int dst;\n        int hval;\n        int nextCur;\n        State st;\n    };\n    Cand cand[MMAX - 1];\n    int cnt = 0;\n\n    for (int dst = 0; dst < M; ++dst) {\n        if (dst == s) continue;\n        cand[cnt].dst = dst;\n        cand[cnt].st = st;\n        move_blockers(cand[cnt].st, dst);\n        pop_all(cand[cnt].st, nullptr);\n        cand[cnt].hval = estimate(cand[cnt].st, mode);\n        cand[cnt].nextCur = cand[cnt].st.cur;\n        ++cnt;\n    }\n\n    array<int, MMAX - 1> ord{};\n    iota(ord.begin(), ord.begin() + cnt, 0);\n    sort(ord.begin(), ord.begin() + cnt, [&](int i, int j) {\n        if (cand[i].hval != cand[j].hval) return cand[i].hval < cand[j].hval;\n        if (cand[i].nextCur != cand[j].nextCur) return cand[i].nextCur > cand[j].nextCur;\n        return cand[i].dst < cand[j].dst;\n    });\n\n    int limit = cnt;\n    if (depth >= 2) limit = min(limit, 5);\n\n    for (int k = 0; k < limit; ++k) {\n        const auto& c = cand[ord[k]];\n        best = min(best, len + 1 + lookahead_cost(c.st, depth - 1, mode));\n    }\n    return best;\n}\n\nResult greedy_complete(State st, int mode, int depth) {\n    Result res;\n    res.energy = 0;\n\n    while (st.cur <= N) {\n        int cur = st.cur;\n        int s = st.st_of[cur];\n        int p = st.pos[cur];\n\n        if (p + 1 >= (int)st.h[s]) {\n            pop_all(st, &res.ops);\n            continue;\n        }\n\n        int len = (int)st.h[s] - p - 1;\n        int v = st.a[s][p + 1];\n\n        int bestDst = -1;\n        int bestVal = INF;\n        int bestCur = -1;\n        int bestH = INF;\n\n        for (int dst = 0; dst < M; ++dst) {\n            if (dst == s) continue;\n            State nx = st;\n            move_blockers(nx, dst);\n            pop_all(nx, nullptr);\n            int hval = estimate(nx, mode);\n            int val = len + 1 + (depth > 1 ? lookahead_cost(nx, depth - 1, mode) : hval);\n\n            if (val < bestVal ||\n                (val == bestVal && nx.cur > bestCur) ||\n                (val == bestVal && nx.cur == bestCur && hval < bestH) ||\n                (val == bestVal && nx.cur == bestCur && hval == bestH && dst < bestDst)) {\n                bestVal = val;\n                bestDst = dst;\n                bestCur = nx.cur;\n                bestH = hval;\n            }\n        }\n\n        res.ops.push_back({v, bestDst + 1});\n        res.energy += len + 1;\n        move_blockers(st, bestDst);\n        pop_all(st, &res.ops);\n    }\n\n    return res;\n}\n\nvector<uint8_t> collect_destinations(const vector<Node>& nodes, int idx) {\n    vector<uint8_t> rev;\n    while (idx != -1 && nodes[idx].parent != -1) {\n        rev.push_back(nodes[idx].actionTo);\n        idx = nodes[idx].parent;\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nstruct ReplayResult {\n    State st;\n    int energy = 0;\n    vector<pair<int,int>> ops;\n};\n\nReplayResult replay_destinations(const State& rawInit, const vector<uint8_t>& dests) {\n    ReplayResult rr;\n    rr.st = rawInit;\n    rr.energy = 0;\n    rr.ops.clear();\n\n    pop_all(rr.st, &rr.ops);\n\n    for (uint8_t to : dests) {\n        if (rr.st.cur > N) break;\n\n        int cur = rr.st.cur;\n        int s = rr.st.st_of[cur];\n        int p = rr.st.pos[cur];\n\n        if (p + 1 >= (int)rr.st.h[s]) {\n            pop_all(rr.st, &rr.ops);\n            continue;\n        }\n\n        int v = rr.st.a[s][p + 1];\n        int len = (int)rr.st.h[s] - p - 1;\n\n        rr.ops.push_back({v, (int)to});\n        rr.energy += len + 1;\n        move_blockers(rr.st, (int)to - 1);\n        pop_all(rr.st, &rr.ops);\n    }\n    return rr;\n}\n\nbool validate_result(const State& rawInit, const Result& res) {\n    State st = rawInit;\n    int energy = 0;\n\n    for (auto [v, to] : res.ops) {\n        if (to == 0) {\n            if (st.cur != v) return false;\n            if (v < 1 || v > N) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            if ((int)st.pos[v] + 1 != (int)st.h[s]) return false;\n            --st.h[s];\n            st.st_of[v] = REMOVED;\n            ++st.cur;\n        } else {\n            if (v < 1 || v > N || to < 1 || to > M) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            int p = st.pos[v];\n            int dst = to - 1;\n            int len = (int)st.h[s] - p;\n            for (int i = p; i < (int)st.h[s]; ++i) {\n                uint16_t x = st.a[s][i];\n                st.a[dst][st.h[dst]] = x;\n                st.st_of[x] = (uint8_t)dst;\n                st.pos[x] = st.h[dst];\n                ++st.h[dst];\n            }\n            st.h[s] = (uint8_t)p;\n            energy += len + 1;\n        }\n    }\n    return st.cur == N + 1 && energy == res.energy && (int)res.ops.size() <= 5000;\n}\n\nResult run_beam(const State& rawInit, const Config& cfg, double deadline) {\n    State start = rawInit;\n    pop_all(start, nullptr);\n\n    vector<Node> nodes;\n    nodes.reserve(cfg.width * 260 + 10);\n    nodes.push_back(Node{start, 0, -1, 0});\n\n    if (start.cur > N) {\n        ReplayResult rr = replay_destinations(rawInit, {});\n        return Result{rr.energy, rr.ops};\n    }\n\n    vector<int> beam = {0};\n    int bestFinishedIdx = -1;\n    int bestFinishedCost = INF;\n\n    while (!beam.empty()) {\n        if (elapsed_sec() > deadline) break;\n\n        vector<TempChild> cand;\n        cand.reserve(beam.size() * (M - 1));\n\n        bool hasBestTemp = false;\n        TempChild bestTemp{};\n\n        for (int idx : beam) {\n            const Node& nd = nodes[idx];\n            const State& st = nd.st;\n\n            if (st.cur > N) {\n                if (nd.g < bestFinishedCost) {\n                    bestFinishedCost = nd.g;\n                    bestFinishedIdx = idx;\n                }\n                continue;\n            }\n\n            int cur = st.cur;\n            int s = st.st_of[cur];\n            int p = st.pos[cur];\n\n            if (p + 1 >= (int)st.h[s]) continue;\n\n            int len = (int)st.h[s] - p - 1;\n\n            for (int dst = 0; dst < M; ++dst) {\n                if (dst == s) continue;\n\n                TempChild tc;\n                tc.st = st;\n                move_blockers(tc.st, dst);\n                pop_all(tc.st, nullptr);\n                tc.g = nd.g + len + 1;\n                tc.hval = estimate(tc.st, cfg.mode);\n                tc.eval = tc.g + tc.hval;\n                tc.parent = idx;\n                tc.actionTo = (uint8_t)(dst + 1);\n                tc.cur = tc.st.cur;\n\n                if (tc.st.cur > N) {\n                    if (tc.g < bestFinishedCost &&\n                        (!hasBestTemp || tc.g < bestTemp.g)) {\n                        hasBestTemp = true;\n                        bestTemp = tc;\n                    }\n                } else {\n                    cand.push_back(std::move(tc));\n                }\n            }\n        }\n\n        if (hasBestTemp) {\n            nodes.push_back(Node{bestTemp.st, bestTemp.g, bestTemp.parent, bestTemp.actionTo});\n            bestFinishedIdx = (int)nodes.size() - 1;\n            bestFinishedCost = bestTemp.g;\n        }\n\n        if (cand.empty()) break;\n\n        vector<int> ord(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n        auto cmp = [&](int i, int j) {\n            const auto& A = cand[i];\n            const auto& B = cand[j];\n            if (A.eval != B.eval) return A.eval < B.eval;\n            if (A.hval != B.hval) return A.hval < B.hval;\n            if (A.cur != B.cur) return A.cur > B.cur;\n            if (A.g != B.g) return A.g < B.g;\n            return A.actionTo < B.actionTo;\n        };\n\n        if ((int)ord.size() > cfg.width) {\n            nth_element(ord.begin(), ord.begin() + cfg.width, ord.end(), cmp);\n            ord.resize(cfg.width);\n        }\n        sort(ord.begin(), ord.end(), cmp);\n\n        vector<int> nextBeam;\n        nextBeam.reserve(ord.size());\n        for (int id : ord) {\n            const auto& tc = cand[id];\n            nodes.push_back(Node{tc.st, tc.g, tc.parent, tc.actionTo});\n            nextBeam.push_back((int)nodes.size() - 1);\n        }\n        beam.swap(nextBeam);\n    }\n\n    Result best;\n    best.energy = INF;\n\n    if (bestFinishedIdx != -1) {\n        auto dests = collect_destinations(nodes, bestFinishedIdx);\n        ReplayResult rr = replay_destinations(rawInit, dests);\n        if (rr.st.cur == N + 1) {\n            best.energy = rr.energy;\n            best.ops = std::move(rr.ops);\n        }\n    }\n\n    for (int t = 0; t < (int)beam.size() && t < 3 && elapsed_sec() <= deadline + 0.02; ++t) {\n        int idx = beam[t];\n        auto dests = collect_destinations(nodes, idx);\n        ReplayResult pref = replay_destinations(rawInit, dests);\n        Result tail = greedy_complete(pref.st, cfg.mode, cfg.greedyDepth);\n\n        Result candRes;\n        candRes.energy = pref.energy + tail.energy;\n        candRes.ops = std::move(pref.ops);\n        candRes.ops.insert(candRes.ops.end(), tail.ops.begin(), tail.ops.end());\n\n        if (candRes.energy < best.energy ||\n            (candRes.energy == best.energy && candRes.ops.size() < best.ops.size())) {\n            best = std::move(candRes);\n        }\n    }\n\n    if (best.energy == INF) {\n        ReplayResult pref = replay_destinations(rawInit, {});\n        Result tail = greedy_complete(pref.st, cfg.mode, max(1, cfg.greedyDepth));\n        best.energy = pref.energy + tail.energy;\n        best.ops = std::move(pref.ops);\n        best.ops.insert(best.ops.end(), tail.ops.begin(), tail.ops.end());\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    global_start = chrono::steady_clock::now();\n\n    cin >> N >> M;\n\n    State rawInit{};\n    rawInit.cur = 1;\n    for (int i = 0; i < M; ++i) {\n        rawInit.h[i] = N / M;\n        for (int j = 0; j < N / M; ++j) {\n            int x;\n            cin >> x;\n            rawInit.a[i][j] = (uint16_t)x;\n            rawInit.st_of[x] = (uint8_t)i;\n            rawInit.pos[x] = (uint8_t)j;\n        }\n    }\n\n    // Tighter internal deadline for robustness.\n    const double deadline = 1.82;\n\n    vector<Config> configs = {\n        {180, 0, 2},\n        {120, 1, 2},\n        {80,  3, 1},\n        {1,   0, 2},\n        {1,   1, 2},\n    };\n\n    Result best;\n    best.energy = INF;\n\n    for (int i = 0; i < (int)configs.size(); ++i) {\n        if (elapsed_sec() > deadline) break;\n        Result cur = run_beam(rawInit, configs[i], deadline);\n        if (validate_result(rawInit, cur)) {\n            if (cur.energy < best.energy ||\n                (cur.energy == best.energy && cur.ops.size() < best.ops.size())) {\n                best = std::move(cur);\n            }\n        }\n    }\n\n    // Absolute safe fallback.\n    if (best.energy == INF) {\n        Result cur = greedy_complete(rawInit, 0, 2);\n        if (!validate_result(rawInit, cur)) {\n            cur = greedy_complete(rawInit, 1, 1);\n        }\n        best = std::move(cur);\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF64 = (1LL << 62);\nstatic constexpr int MAXV = 1600;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = chrono::steady_clock::now().time_since_epoch().count()) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next() % (uint64_t)n); }\n    double next_double() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Score {\n    long long num;\n    int L;\n};\n\nstatic inline bool better_score(const Score& a, const Score& b) {\n    __int128 lhs = (__int128)a.num * b.L;\n    __int128 rhs = (__int128)b.num * a.L;\n    if (lhs != rhs) return lhs < rhs;\n    return a.L < b.L;\n}\n\nstruct State {\n    vector<int> parent;\n    vector<int> sz;\n    vector<int> depth;\n    vector<int> tin, tout;\n    vector<long long> subD;\n    long long num = INF64;\n};\n\nstruct Comp {\n    string route;\n    vector<int> pos; // pos[0] = 0\n    int len = 0;\n};\n\nint N, Vn;\nint TREE_LEN;\nvector<int> g[MAXV];\nint dirtv[MAXV];\nlong long sqrtv_[MAXV];\nlong long imp1[MAXV], imp2[MAXV], imp3[MAXV], imp4[MAXV];\nint distRoot[MAXV];\nint bfsParent[MAXV];\n\nint firstOcc[MAXV], lastOcc[MAXV];\nlong long gapAcc[MAXV];\n\nXorShift64 rng;\n\ninline int vid(int r, int c) { return r * N + c; }\n\ninline char move_char(int a, int b) {\n    if (b == a + 1) return 'R';\n    if (b == a - 1) return 'L';\n    if (b == a + N) return 'D';\n    return 'U';\n}\n\ninline long long tri(long long x) {\n    return x * (x - 1) / 2;\n}\n\ninline long long node_term(int x, int szx, int parentD) {\n    long long g1 = TREE_LEN - 2LL * (szx - 1); // outside gap for x\n    long long g2 = 2LL * szx;                  // child-subtree gap for parent(x)\n    return 1LL * dirtv[x] * tri(g1) + 1LL * parentD * tri(g2);\n}\n\nvoid compute_root_bfs() {\n    fill(distRoot, distRoot + Vn, -1);\n    fill(bfsParent, bfsParent + Vn, -1);\n    queue<int> q;\n    distRoot[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int u = q.front();\n        q.pop();\n        for (int to : g[u]) {\n            if (distRoot[to] == -1) {\n                distRoot[to] = distRoot[u] + 1;\n                bfsParent[to] = u;\n                q.push(to);\n            }\n        }\n    }\n}\n\nState build_state(const vector<int>& parent) {\n    State st;\n    st.parent = parent;\n    st.sz.assign(Vn, 1);\n    st.depth.assign(Vn, 0);\n    st.tin.assign(Vn, 0);\n    st.tout.assign(Vn, 0);\n    st.subD.assign(Vn, 0);\n\n    vector<vector<int>> ch(Vn);\n    for (int v = 1; v < Vn; v++) ch[parent[v]].push_back(v);\n\n    vector<int> order;\n    order.reserve(Vn);\n    int timer = 0;\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        st.tin[u] = timer++;\n        for (int c : ch[u]) {\n            st.depth[c] = st.depth[u] + 1;\n            self(self, c);\n        }\n        st.tout[u] = timer;\n        order.push_back(u); // postorder\n    };\n    dfs(dfs, 0);\n\n    for (int u : order) {\n        st.sz[u] = 1;\n        st.subD[u] = dirtv[u];\n        for (int c : ch[u]) {\n            st.sz[u] += st.sz[c];\n            st.subD[u] += st.subD[c];\n        }\n    }\n\n    long long num = 0;\n    for (int x = 1; x < Vn; x++) {\n        num += node_term(x, st.sz[x], dirtv[st.parent[x]]);\n    }\n    st.num = num;\n    return st;\n}\n\nint lca_slow(const State& st, int a, int b) {\n    while (st.depth[a] > st.depth[b]) a = st.parent[a];\n    while (st.depth[b] > st.depth[a]) b = st.parent[b];\n    while (a != b) {\n        a = st.parent[a];\n        b = st.parent[b];\n    }\n    return a;\n}\n\ninline bool is_descendant(const State& st, int x, int anc) {\n    return st.tin[anc] <= st.tin[x] && st.tout[x] <= st.tout[anc];\n}\n\nlong long delta_reparent(const State& st, int u, int w) {\n    int p = st.parent[u];\n    int s = st.sz[u];\n    int l = lca_slow(st, p, w);\n\n    long long delta = 0;\n\n    // u itself: size unchanged, parent dirt changes\n    delta += node_term(u, s, dirtv[w]) - node_term(u, s, dirtv[p]);\n\n    // ancestors on old-parent side lose s\n    for (int x = p; x != l; x = st.parent[x]) {\n        delta += node_term(x, st.sz[x] - s, dirtv[st.parent[x]]) - node_term(x, st.sz[x], dirtv[st.parent[x]]);\n    }\n\n    // ancestors on new-parent side gain s\n    for (int x = w; x != l; x = st.parent[x]) {\n        delta += node_term(x, st.sz[x] + s, dirtv[st.parent[x]]) - node_term(x, st.sz[x], dirtv[st.parent[x]]);\n    }\n\n    return delta;\n}\n\nvector<int> gen_spt(const long long* imp) {\n    vector<int> parent(Vn, -1);\n    for (int u = 1; u < Vn; u++) {\n        int best = -1;\n        for (int p : g[u]) {\n            if (distRoot[p] == distRoot[u] - 1) {\n                if (best == -1 || imp[p] > imp[best] || (imp[p] == imp[best] && p < best)) {\n                    best = p;\n                }\n            }\n        }\n        parent[u] = best;\n    }\n    return parent;\n}\n\nlong long rand_noise(long long amp) {\n    if (amp == 0) return 0;\n    return (long long)(rng.next() % (uint64_t)(2 * amp + 1)) - amp;\n}\n\nvector<int> gen_weighted_dfs(const long long* imp, long long noise) {\n    vector<int> parent(Vn, -1);\n    vector<char> vis(Vn, 0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        vis[u] = 1;\n        vector<pair<long long, int>> cand;\n        cand.reserve(g[u].size());\n        for (int to : g[u]) {\n            cand.push_back({imp[to] + rand_noise(noise), to});\n        }\n        sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        for (auto& e : cand) {\n            int to = e.second;\n            if (!vis[to]) {\n                parent[to] = u;\n                self(self, to);\n            }\n        }\n    };\n    dfs(dfs, 0);\n    return parent;\n}\n\nvector<int> gen_prim(const long long* imp, long long noise, int depthPenalty) {\n    struct Node {\n        long long key;\n        uint64_t tie;\n        int from, to;\n        bool operator<(const Node& other) const {\n            if (key != other.key) return key < other.key;\n            return tie < other.tie;\n        }\n    };\n\n    vector<int> parent(Vn, -1), depth(Vn, 0);\n    vector<char> used(Vn, 0);\n    priority_queue<Node> pq;\n\n    auto push_edges = [&](int u) {\n        for (int to : g[u]) if (!used[to]) {\n            long long key = imp[to] - 1LL * depthPenalty * depth[u] + rand_noise(noise);\n            pq.push({key, rng.next(), u, to});\n        }\n    };\n\n    used[0] = 1;\n    int cnt = 1;\n    push_edges(0);\n\n    while (!pq.empty() && cnt < Vn) {\n        auto cur = pq.top();\n        pq.pop();\n        if (used[cur.to]) continue;\n        used[cur.to] = 1;\n        parent[cur.to] = cur.from;\n        depth[cur.to] = depth[cur.from] + 1;\n        cnt++;\n        push_edges(cur.to);\n    }\n\n    if (cnt < Vn) return gen_weighted_dfs(imp, 0);\n    return parent;\n}\n\nvector<int> random_parent_candidate(const vector<const long long*>& imps, const vector<int>& sptA, const vector<int>& sptB) {\n    int typ = rng.next_int(8);\n    if (typ == 0) return sptA;\n    if (typ == 1) return sptB;\n    if (typ <= 4) {\n        const long long* imp = imps[rng.next_int((int)imps.size())];\n        static const long long noises[] = {0, 4000, 12000, 40000, 80000};\n        return gen_weighted_dfs(imp, noises[rng.next_int((int)(sizeof(noises) / sizeof(noises[0])))]);\n    } else {\n        const long long* imp = imps[rng.next_int((int)imps.size())];\n        static const long long noises[] = {0, 6000, 20000, 50000};\n        static const int pens[] = {0, 100, 250, 500};\n        return gen_prim(imp, noises[rng.next_int((int)(sizeof(noises) / sizeof(noises[0])))],\n                        pens[rng.next_int((int)(sizeof(pens) / sizeof(pens[0])))]);\n    }\n}\n\nvoid consider_pool(vector<State>& pool, const State& st, int maxPool = 8) {\n    if ((int)pool.size() >= maxPool && st.num >= pool.back().num) return;\n    pool.push_back(st);\n    sort(pool.begin(), pool.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n    if ((int)pool.size() > maxPool) pool.pop_back();\n}\n\nvector<int> make_top_list_static() {\n    vector<pair<long long, int>> cand;\n    cand.reserve(Vn * 4);\n\n    for (int u = 1; u < Vn; u++) {\n        cand.push_back({1LL * dirtv[u] * 1000000LL, u});\n        cand.push_back({sqrtv_[u] * 1000000LL, u});\n        cand.push_back({(distRoot[u] >= 0 ? 1LL * dirtv[u] * 1000000LL / (distRoot[u] + 1) : 0), u});\n        cand.push_back({(distRoot[u] >= 0 ? sqrtv_[u] * 1000000LL / (distRoot[u] + 1) : 0), u});\n    }\n\n    sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n        if (A.first != B.first) return A.first > B.first;\n        return A.second < B.second;\n    });\n\n    vector<int> res;\n    vector<char> used(Vn, 0);\n    for (auto& e : cand) {\n        int u = e.second;\n        if (!used[u]) {\n            used[u] = 1;\n            res.push_back(u);\n            if ((int)res.size() >= 256) break;\n        }\n    }\n    return res;\n}\n\nvector<int> make_top_bad(const State& st) {\n    vector<pair<long long, int>> vec;\n    vec.reserve(Vn - 1);\n    for (int x = 1; x < Vn; x++) {\n        vec.push_back({node_term(x, st.sz[x], dirtv[st.parent[x]]), x});\n    }\n    sort(vec.begin(), vec.end(), [&](auto& A, auto& B) {\n        if (A.first != B.first) return A.first > B.first;\n        return A.second < B.second;\n    });\n    vector<int> res;\n    for (int i = 0; i < (int)vec.size() && i < 256; i++) res.push_back(vec[i].second);\n    return res;\n}\n\nvoid build_children_sorted(const State& st, vector<vector<int>>& ch) {\n    ch.assign(Vn, {});\n    for (int v = 1; v < Vn; v++) ch[st.parent[v]].push_back(v);\n    for (int u = 0; u < Vn; u++) {\n        sort(ch[u].begin(), ch[u].end(), [&](int a, int b) {\n            if (st.subD[a] != st.subD[b]) return st.subD[a] > st.subD[b];\n            return a < b;\n        });\n    }\n}\n\nComp build_global_route(const State& st) {\n    vector<vector<int>> ch;\n    build_children_sorted(st, ch);\n\n    Comp C;\n    C.route.reserve(TREE_LEN);\n    C.pos.reserve(TREE_LEN + 1);\n    C.pos.push_back(0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        for (int c : ch[u]) {\n            C.route.push_back(move_char(u, c));\n            C.pos.push_back(c);\n            self(self, c);\n            C.route.push_back(move_char(c, u));\n            C.pos.push_back(u);\n        }\n    };\n    dfs(dfs, 0);\n\n    C.len = (int)C.route.size();\n    return C;\n}\n\nComp build_path_loop(int target) {\n    vector<int> fwd;\n    for (int x = target; x != 0; x = bfsParent[x]) fwd.push_back(x);\n    reverse(fwd.begin(), fwd.end());\n\n    Comp C;\n    C.pos.reserve(2 * (int)fwd.size() + 1);\n    C.pos.push_back(0);\n    for (int v : fwd) C.pos.push_back(v);\n    for (int i = (int)fwd.size() - 2; i >= 0; i--) C.pos.push_back(fwd[i]);\n    C.pos.push_back(0);\n\n    C.route.reserve((int)C.pos.size() - 1);\n    for (int i = 1; i < (int)C.pos.size(); i++) {\n        C.route.push_back(move_char(C.pos[i - 1], C.pos[i]));\n    }\n    C.len = (int)C.route.size();\n    return C;\n}\n\nComp build_subtree_loop(const State& st, int rootSub) {\n    vector<vector<int>> ch;\n    build_children_sorted(st, ch);\n\n    vector<int> path;\n    for (int x = rootSub; x != 0; x = st.parent[x]) path.push_back(x);\n    reverse(path.begin(), path.end());\n\n    Comp C;\n    C.pos.reserve(2 * (st.depth[rootSub] + st.sz[rootSub] - 1) + 1);\n    C.pos.push_back(0);\n    for (int v : path) C.pos.push_back(v);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        for (int c : ch[u]) {\n            C.route.push_back(move_char(u, c));\n            C.pos.push_back(c);\n            self(self, c);\n            C.route.push_back(move_char(c, u));\n            C.pos.push_back(u);\n        }\n    };\n    dfs(dfs, rootSub);\n\n    for (int i = (int)path.size() - 2; i >= 0; i--) {\n        C.pos.push_back(path[i]);\n    }\n    C.pos.push_back(0);\n\n    C.route.clear();\n    C.route.reserve((int)C.pos.size() - 1);\n    for (int i = 1; i < (int)C.pos.size(); i++) {\n        C.route.push_back(move_char(C.pos[i - 1], C.pos[i]));\n    }\n    C.len = (int)C.route.size();\n    return C;\n}\n\nScore evaluate_positions(const vector<int>& pos) {\n    int L = (int)pos.size() - 1;\n    fill(firstOcc, firstOcc + Vn, -1);\n    fill(gapAcc, gapAcc + Vn, 0LL);\n\n    long long num = 0;\n    for (int t = 1; t <= L; t++) {\n        int x = pos[t];\n        if (firstOcc[x] == -1) {\n            firstOcc[x] = t;\n        } else {\n            long long g = t - lastOcc[x];\n            gapAcc[x] += g * (g - 1) / 2;\n        }\n        lastOcc[x] = t;\n    }\n    for (int x = 0; x < Vn; x++) {\n        if (firstOcc[x] == -1) return {INF64, L};\n        long long g = firstOcc[x] + L - lastOcc[x];\n        gapAcc[x] += g * (g - 1) / 2;\n        num += gapAcc[x] * 1LL * dirtv[x];\n    }\n    return {num, L};\n}\n\nScore evaluate_combo(const Comp& H, int k, const Comp& G) {\n    static vector<int> pos;\n    pos.clear();\n    pos.reserve(1 + k * H.len + G.len);\n    pos.push_back(0);\n    for (int rep = 0; rep < k; rep++) {\n        pos.insert(pos.end(), H.pos.begin() + 1, H.pos.end());\n    }\n    pos.insert(pos.end(), G.pos.begin() + 1, G.pos.end());\n    return evaluate_positions(pos);\n}\n\nvector<int> make_k_list(int limit) {\n    vector<int> ks;\n    for (int k = 1; k <= min(limit, 12); k++) ks.push_back(k);\n    for (int k = 16; k <= limit; ) {\n        ks.push_back(k);\n        int nk = k + max(2, k / 2);\n        if (nk == k) nk++;\n        k = nk;\n    }\n    if (limit > 0) ks.push_back(limit);\n    sort(ks.begin(), ks.end());\n    ks.erase(unique(ks.begin(), ks.end()), ks.end());\n    return ks;\n}\n\nvoid add_refine(vector<int>& ks, int limit, int center) {\n    int L = max(1, center - 10);\n    int R = min(limit, center + 10);\n    for (int k = L; k <= R; k++) ks.push_back(k);\n    sort(ks.begin(), ks.end());\n    ks.erase(unique(ks.begin(), ks.end()), ks.end());\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<string> h(N - 1), vwall(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vwall[i];\n\n    Vn = N * N;\n    TREE_LEN = 2 * (Vn - 1);\n\n    for (int i = 0; i < Vn; i++) g[i].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> dirtv[vid(i, j)];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int a = vid(i, j);\n            if (i + 1 < N && h[i][j] == '0') {\n                int b = vid(i + 1, j);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int b = vid(i, j + 1);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n        }\n    }\n\n    for (int u = 0; u < Vn; u++) {\n        sqrtv_[u] = llround(1000.0 * sqrt((double)dirtv[u]));\n    }\n    for (int u = 0; u < Vn; u++) {\n        long long s1 = 0, s2 = 0;\n        for (int to : g[u]) {\n            s1 += dirtv[to];\n            s2 += sqrtv_[to];\n        }\n        imp1[u] = dirtv[u];\n        imp2[u] = sqrtv_[u];\n        imp3[u] = 100LL * dirtv[u] + 35LL * s1;\n        imp4[u] = 100LL * sqrtv_[u] + 35LL * s2;\n    }\n\n    compute_root_bfs();\n\n    vector<const long long*> imps = {imp1, imp2, imp3, imp4};\n    vector<int> sptRaw = gen_spt(imp3);\n    vector<int> sptSqrt = gen_spt(imp4);\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\n    vector<State> pool;\n\n    auto add_parent = [&](const vector<int>& parent) {\n        State st = build_state(parent);\n        consider_pool(pool, st);\n    };\n\n    // Initial candidates\n    add_parent(sptRaw);\n    add_parent(sptSqrt);\n    for (const long long* imp : imps) {\n        for (long long nz : {0LL, 3000LL, 10000LL, 30000LL, 70000LL}) {\n            int reps = (nz == 0 ? 1 : 2);\n            for (int rep = 0; rep < reps; rep++) add_parent(gen_weighted_dfs(imp, nz));\n        }\n        for (long long nz : {0LL, 5000LL, 15000LL, 40000LL}) {\n            for (int pen : {0, 80, 200, 400}) add_parent(gen_prim(imp, nz, pen));\n        }\n    }\n\n    if (pool.empty()) {\n        add_parent(sptRaw);\n    }\n\n    State best = pool[0];\n    State current = best;\n\n    vector<int> staticHot = make_top_list_static();\n    vector<int> topBad = make_top_bad(current);\n\n    int stall = 0;\n    const double SEARCH_TL = 1.76;\n\n    while (elapsed() < SEARCH_TL) {\n        if (stall >= 260) {\n            if (!pool.empty() && rng.next_int(100) < 80) {\n                current = pool[rng.next_int(min(4, (int)pool.size()))];\n            } else {\n                current = build_state(random_parent_candidate(imps, sptRaw, sptSqrt));\n                consider_pool(pool, current);\n            }\n            topBad = make_top_bad(current);\n            stall = 0;\n            continue;\n        }\n\n        long long bestDeltaAny = INF64;\n        int bestuAny = -1, bestwAny = -1;\n        long long bestDeltaImp = 0;\n        int bestuImp = -1, bestwImp = -1;\n\n        const int SAMPLES = 40;\n        for (int it = 0; it < SAMPLES; it++) {\n            int u;\n            int r = rng.next_int(100);\n            if (r < 45 && !topBad.empty()) {\n                u = topBad[rng.next_int(min(160, (int)topBad.size()))];\n            } else if (r < 80 && !staticHot.empty()) {\n                u = staticHot[rng.next_int(min(160, (int)staticHot.size()))];\n            } else {\n                u = 1 + rng.next_int(Vn - 1);\n            }\n\n            long long localBest = INF64;\n            int localW = -1;\n\n            for (int w : g[u]) {\n                if (w == current.parent[u]) continue;\n                if (is_descendant(current, w, u)) continue;\n                long long delta = delta_reparent(current, u, w);\n                if (delta < localBest) {\n                    localBest = delta;\n                    localW = w;\n                }\n            }\n\n            if (localW != -1) {\n                if (localBest < bestDeltaAny) {\n                    bestDeltaAny = localBest;\n                    bestuAny = u;\n                    bestwAny = localW;\n                }\n                if (localBest < bestDeltaImp) {\n                    bestDeltaImp = localBest;\n                    bestuImp = u;\n                    bestwImp = localW;\n                }\n            }\n        }\n\n        bool accept = false;\n        int au = -1, aw = -1;\n\n        if (bestuImp != -1) {\n            accept = true;\n            au = bestuImp;\n            aw = bestwImp;\n        } else if (bestuAny != -1) {\n            double p = elapsed() / SEARCH_TL;\n            double T = 150000.0 * pow(0.01, p); // on absolute-score scale\n            double deltaAbs = (double)bestDeltaAny / TREE_LEN;\n            double prob = exp(-deltaAbs / T);\n            if (rng.next_double() < prob) {\n                accept = true;\n                au = bestuAny;\n                aw = bestwAny;\n            }\n        }\n\n        if (accept) {\n            current.parent[au] = aw;\n            current = build_state(current.parent);\n            topBad = make_top_bad(current);\n            consider_pool(pool, current);\n            if (current.num < best.num) best = current;\n            if (bestuImp != -1) stall = 0;\n            else stall++;\n        } else {\n            stall++;\n        }\n    }\n\n    // Final greedy polishing around the current best\n    current = best;\n    topBad = make_top_bad(current);\n    while (elapsed() < 1.88) {\n        long long bestDelta = 0;\n        int bestu = -1, bestw = -1;\n\n        int lim1 = min(120, (int)topBad.size());\n        for (int idx = 0; idx < lim1; idx++) {\n            int u = topBad[idx];\n            for (int w : g[u]) {\n                if (w == current.parent[u]) continue;\n                if (is_descendant(current, w, u)) continue;\n                long long delta = delta_reparent(current, u, w);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestu = u;\n                    bestw = w;\n                }\n            }\n        }\n\n        int lim2 = min(80, (int)staticHot.size());\n        for (int idx = 0; idx < lim2; idx++) {\n            int u = staticHot[idx];\n            for (int w : g[u]) {\n                if (w == current.parent[u]) continue;\n                if (is_descendant(current, w, u)) continue;\n                long long delta = delta_reparent(current, u, w);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestu = u;\n                    bestw = w;\n                }\n            }\n        }\n\n        if (bestu == -1) break;\n        current.parent[bestu] = bestw;\n        current = build_state(current.parent);\n        topBad = make_top_bad(current);\n        if (current.num < best.num) best = current;\n    }\n\n    // Base route from the best tree\n    Comp G = build_global_route(best);\n    Score bestScore = evaluate_positions(G.pos);\n    string bestRoute = G.route;\n\n    // Optional very short loops only if exact evaluation improves\n    vector<Comp> loops;\n\n    // Short path loops near root\n    {\n        vector<pair<long long, int>> cand;\n        for (int u = 1; u < Vn; u++) {\n            if (distRoot[u] >= 0 && distRoot[u] <= 6) {\n                long long key1 = 1LL * dirtv[u] * 1000000LL / ((distRoot[u] + 1) * (distRoot[u] + 1));\n                long long key2 = sqrtv_[u] * 1000000LL / ((distRoot[u] + 1) * (distRoot[u] + 1));\n                cand.push_back({max(key1, key2), u});\n            }\n        }\n        sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        vector<char> used(Vn, 0);\n        int cnt = 0;\n        for (auto& e : cand) {\n            int u = e.second;\n            if (used[u]) continue;\n            used[u] = 1;\n            Comp H = build_path_loop(u);\n            if (H.len > 0 && H.len <= 14) {\n                loops.push_back(move(H));\n                cnt++;\n                if (cnt >= 6) break;\n            }\n        }\n    }\n\n    // Small hot subtrees near root in the best tree\n    {\n        vector<pair<long long, int>> cand;\n        for (int u = 1; u < Vn; u++) {\n            int loopLen = 2 * (best.depth[u] + best.sz[u] - 1);\n            if (loopLen <= 40 && best.depth[u] <= 8) {\n                long long key = best.subD[u] * 1000000LL / max(1, loopLen * loopLen);\n                cand.push_back({key, u});\n            }\n        }\n        sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        vector<char> used(Vn, 0);\n        int cnt = 0;\n        for (auto& e : cand) {\n            int u = e.second;\n            if (used[u]) continue;\n            used[u] = 1;\n            Comp H = build_subtree_loop(best, u);\n            if (H.len > 0 && H.len <= 40) {\n                loops.push_back(move(H));\n                cnt++;\n                if (cnt >= 8) break;\n            }\n        }\n    }\n\n    // Try each short loop repeated before the global route\n    for (const Comp& H : loops) {\n        int limit = (100000 - G.len) / H.len;\n        if (limit <= 0) continue;\n\n        vector<int> ks = make_k_list(limit);\n        int bestK = 0;\n        Score localBest = bestScore;\n\n        for (int k : ks) {\n            Score sc = evaluate_combo(H, k, G);\n            if (better_score(sc, localBest)) {\n                localBest = sc;\n                bestK = k;\n            }\n        }\n\n        add_refine(ks, limit, bestK);\n        for (int k : ks) {\n            Score sc = evaluate_combo(H, k, G);\n            if (better_score(sc, localBest)) {\n                localBest = sc;\n                bestK = k;\n            }\n        }\n\n        if (bestK > 0 && better_score(localBest, bestScore)) {\n            bestScore = localBest;\n            string route;\n            route.reserve(bestK * H.len + G.len);\n            for (int rep = 0; rep < bestK; rep++) route += H.route;\n            route += G.route;\n            bestRoute = move(route);\n        }\n    }\n\n    cout << bestRoute << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"Ofast,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool same(int a, int b) { return find(a) == find(b); }\n    bool unite(int a, int b) {\n        a = find(a), b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int PMAX = 225;\n    static constexpr int MMAX = 200;\n    static constexpr int INF = 1e9;\n\n    int N, M;\n    int si, sj, startPos;\n\n    vector<string> board;\n    vector<string> words;\n    vector<array<int, 5>> w;\n\n    array<vector<int>, 26> occ;\n    int man[PMAX][PMAX];\n\n    int ov[MMAX][MMAX];\n    int lastc[MMAX];\n    int endCnt[MMAX];\n\n    struct MatInfo {\n        vector<uint16_t> a; // row-major\n    };\n    vector<MatInfo> mats; // [26][M][5]\n\n    vector<vector<uint16_t>> startVec; // per word\n    int startMin[MMAX];\n    int startApprox[MMAX];\n    int edgeMin[MMAX][MMAX];\n    int edgeApprox[MMAX][MMAX];\n    int bestOutApprox[MMAX];\n\n    uint32_t baseSeed = 1;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 1.88;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n    inline bool timeup(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline MatInfo& MAT(int c, int j, int st) {\n        return mats[(c * M + j) * 5 + st];\n    }\n    inline const MatInfo& MAT(int c, int j, int st) const {\n        return mats[(c * M + j) * 5 + st];\n    }\n\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        cin >> si >> sj;\n        startPos = si * N + sj;\n\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n\n        words.resize(M);\n        w.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) w[i][k] = words[i][k] - 'A';\n            lastc[i] = w[i][4];\n        }\n    }\n\n    void buildSeed() {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (auto& row : board) for (char c : row) mix((uint64_t)c);\n        for (auto& s : words) for (char c : s) mix((uint64_t)c);\n        baseSeed = (uint32_t)(h ^ (h >> 32));\n        if (baseSeed == 0) baseSeed = 1;\n        rng.seed(baseSeed);\n    }\n\n    void precomputeKeyboard() {\n        for (auto& v : occ) v.clear();\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                occ[board[i][j] - 'A'].push_back(id);\n            }\n        }\n        for (int p = 0; p < N * N; p++) {\n            int pi = p / N, pj = p % N;\n            for (int q = 0; q < N * N; q++) {\n                int qi = q / N, qj = q % N;\n                man[p][q] = abs(pi - qi) + abs(pj - qj);\n            }\n        }\n        for (int i = 0; i < M; i++) endCnt[i] = (int)occ[lastc[i]].size();\n    }\n\n    int calcOverlap(const string& a, const string& b) const {\n        for (int len = 4; len >= 1; len--) {\n            bool ok = true;\n            for (int k = 0; k < len; k++) {\n                if (a[5 - len + k] != b[k]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return len;\n        }\n        return 0;\n    }\n\n    void precomputeOverlaps() {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                ov[i][j] = (i == j ? 0 : calcOverlap(words[i], words[j]));\n            }\n        }\n    }\n\n    vector<uint16_t> buildMatFromSources(const vector<int>& srcPos, int wid, int st) {\n        int R = (int)srcPos.size();\n        int C = endCnt[wid];\n        vector<uint16_t> res(R * C);\n\n        int prevCost[PMAX], curCost[PMAX];\n\n        for (int r = 0; r < R; r++) {\n            int src = srcPos[r];\n\n            int prevChar = w[wid][st];\n            int pcnt = (int)occ[prevChar].size();\n            const vector<int>& firstPos = occ[prevChar];\n            for (int i = 0; i < pcnt; i++) {\n                prevCost[i] = man[src][firstPos[i]] + 1;\n            }\n\n            for (int k = st + 1; k < 5; k++) {\n                int curChar = w[wid][k];\n                const vector<int>& prevPos = occ[prevChar];\n                const vector<int>& curPos = occ[curChar];\n                int ccnt = (int)curPos.size();\n\n                for (int ci = 0; ci < ccnt; ci++) {\n                    int q = curPos[ci];\n                    int best = INF;\n                    for (int pi = 0; pi < pcnt; pi++) {\n                        int cand = prevCost[pi] + man[prevPos[pi]][q] + 1;\n                        if (cand < best) best = cand;\n                    }\n                    curCost[ci] = best;\n                }\n                for (int i = 0; i < ccnt; i++) prevCost[i] = curCost[i];\n                pcnt = ccnt;\n                prevChar = curChar;\n            }\n\n            for (int e = 0; e < C; e++) {\n                res[r * C + e] = (uint16_t)prevCost[e];\n            }\n        }\n        return res;\n    }\n\n    void precomputeMatrices() {\n        mats.resize(26 * M * 5);\n        startVec.assign(M, {});\n\n        for (int j = 0; j < M; j++) {\n            vector<int> src = {startPos};\n            auto v = buildMatFromSources(src, j, 0);\n            startVec[j].assign(v.begin(), v.end());\n\n            int mn = INF, sum = 0;\n            for (uint16_t x : startVec[j]) {\n                mn = min(mn, (int)x);\n                sum += x;\n            }\n            startMin[j] = mn;\n            int avg = sum / max(1, (int)startVec[j].size());\n            startApprox[j] = (mn + avg) / 2;\n        }\n\n        for (int c = 0; c < 26; c++) {\n            for (int j = 0; j < M; j++) {\n                for (int st = 0; st < 5; st++) {\n                    MAT(c, j, st).a = buildMatFromSources(occ[c], j, st);\n                }\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            edgeMin[i][i] = INF / 4;\n            edgeApprox[i][i] = INF / 4;\n            for (int j = 0; j < M; j++) if (i != j) {\n                int c = lastc[i];\n                int st = ov[i][j];\n                const auto& arr = MAT(c, j, st).a;\n                int rows = (int)occ[c].size();\n                int cols = endCnt[j];\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                const uint16_t* p = arr.data();\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    const uint16_t* row = p + r * cols;\n                    for (int e = 0; e < cols; e++) {\n                        int v = row[e];\n                        if (v < rowMin) rowMin = v;\n                        if (v < globalMin) globalMin = v;\n                    }\n                    sumRowMin += rowMin;\n                }\n                int avgRowMin = (int)(sumRowMin / max(1, rows));\n                edgeMin[i][j] = globalMin;\n                edgeApprox[i][j] = (globalMin + avgRowMin) / 2;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            int best = INF;\n            for (int j = 0; j < M; j++) if (i != j) {\n                best = min(best, edgeApprox[i][j]);\n            }\n            bestOutApprox[i] = best;\n        }\n    }\n\n    int evalPerm(const vector<int>& perm) const {\n        if (perm.empty()) return 0;\n\n        int dp[PMAX], ndp[PMAX];\n        int first = perm[0];\n        int cnt = endCnt[first];\n        for (int e = 0; e < cnt; e++) dp[e] = startVec[first][e];\n\n        for (int idx = 1; idx < (int)perm.size(); idx++) {\n            int a = perm[idx - 1];\n            int b = perm[idx];\n            int c = lastc[a];\n            int st = ov[a][b];\n            const auto& arr = MAT(c, b, st).a;\n            int rows = (int)occ[c].size();\n            int cols = endCnt[b];\n\n            for (int e = 0; e < cols; e++) ndp[e] = INF;\n            const uint16_t* matp = arr.data();\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const uint16_t* row = matp + r * cols;\n                for (int e = 0; e < cols; e++) {\n                    int cand = base + row[e];\n                    if (cand < ndp[e]) ndp[e] = cand;\n                }\n            }\n\n            cnt = cols;\n            for (int e = 0; e < cnt; e++) dp[e] = ndp[e];\n        }\n\n        int ans = INF;\n        for (int e = 0; e < cnt; e++) ans = min(ans, dp[e]);\n        return ans;\n    }\n\n    int transitionCostAndDP(const int* dp, int curWord, int nextWord, int* outDP) const {\n        int c = lastc[curWord];\n        int st = ov[curWord][nextWord];\n        const auto& arr = MAT(c, nextWord, st).a;\n        int rows = (int)occ[c].size();\n        int cols = endCnt[nextWord];\n\n        for (int e = 0; e < cols; e++) outDP[e] = INF;\n        const uint16_t* matp = arr.data();\n\n        for (int r = 0; r < rows; r++) {\n            int base = dp[r];\n            const uint16_t* row = matp + r * cols;\n            for (int e = 0; e < cols; e++) {\n                int cand = base + row[e];\n                if (cand < outDP[e]) outDP[e] = cand;\n            }\n        }\n\n        int best = INF;\n        for (int e = 0; e < cols; e++) best = min(best, outDP[e]);\n        return best;\n    }\n\n    string buildString(const vector<int>& perm) const {\n        string s;\n        if (perm.empty()) return s;\n        s.reserve(5 * (int)perm.size());\n        s += words[perm[0]];\n        for (int i = 1; i < (int)perm.size(); i++) {\n            int o = ov[perm[i - 1]][perm[i]];\n            s.append(words[perm[i]].begin() + o, words[perm[i]].end());\n        }\n        return s;\n    }\n\n    // ---------- Initial constructions ----------\n\n    vector<int> initGreedyAppend(int firstWord, uint32_t seed, bool randomized, int topNext = 4) const {\n        mt19937 rr(seed);\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> used(M, 0);\n\n        int curDP[PMAX], tmpDP[PMAX], chosenDP[PMAX];\n\n        perm.push_back(firstWord);\n        used[firstWord] = 1;\n        int curCnt = endCnt[firstWord];\n        for (int e = 0; e < curCnt; e++) curDP[e] = startVec[firstWord][e];\n        int curWord = firstWord;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                int score2;\n                int scoreExact;\n                int j;\n            };\n            vector<Cand> cand;\n            cand.reserve(M - (int)perm.size());\n\n            int remain = M - (int)perm.size();\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                int scoreExact = transitionCostAndDP(curDP, curWord, j, tmpDP);\n                int future = (remain > 1 ? bestOutApprox[j] / 2 : 0);\n                int score2 = scoreExact + future;\n                cand.push_back({score2, scoreExact, j});\n            }\n            sort(cand.begin(), cand.end(), [](const Cand& a, const Cand& b) {\n                if (a.score2 != b.score2) return a.score2 < b.score2;\n                if (a.scoreExact != b.scoreExact) return a.scoreExact < b.scoreExact;\n                return a.j < b.j;\n            });\n\n            int pickIdx = 0;\n            if (randomized) {\n                int lim = min<int>(topNext, cand.size());\n                pickIdx = uniform_int_distribution<int>(0, lim - 1)(rr);\n            }\n            int nxt = cand[pickIdx].j;\n\n            transitionCostAndDP(curDP, curWord, nxt, chosenDP);\n            curCnt = endCnt[nxt];\n            for (int e = 0; e < curCnt; e++) curDP[e] = chosenDP[e];\n\n            perm.push_back(nxt);\n            used[nxt] = 1;\n            curWord = nxt;\n        }\n        return perm;\n    }\n\n    vector<int> initEdgeGreedy(uint32_t seed, bool randomized) const {\n        struct E {\n            int u, v, cost, ovv;\n        };\n        vector<E> edges;\n        edges.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) if (i != j) {\n                edges.push_back({i, j, edgeApprox[i][j], ov[i][j]});\n            }\n        }\n\n        mt19937 rr(seed);\n        if (randomized) shuffle(edges.begin(), edges.end(), rr);\n\n        stable_sort(edges.begin(), edges.end(), [&](const E& a, const E& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.ovv != b.ovv) return a.ovv > b.ovv;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        vector<int> in(M, -1), out(M, -1);\n        DSU dsu(M);\n        int used = 0;\n        for (auto& e : edges) {\n            if (out[e.u] != -1) continue;\n            if (in[e.v] != -1) continue;\n            if (dsu.same(e.u, e.v)) continue;\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n            used++;\n            if (used == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) if (in[i] == -1) {\n            head = i;\n            break;\n        }\n\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> seen(M, 0);\n        int cur = head;\n        while (cur != -1 && !seen[cur]) {\n            perm.push_back(cur);\n            seen[cur] = 1;\n            cur = out[cur];\n        }\n        for (int i = 0; i < M; i++) if (!seen[i]) perm.push_back(i);\n        return perm;\n    }\n\n    vector<int> initExactInsertion(uint32_t seed, bool randomized) const {\n        mt19937 rr(seed);\n        if (M == 1) return {0};\n\n        struct PairCand {\n            int approx;\n            int a, b;\n        };\n        vector<PairCand> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) if (i != j) {\n                pairs.push_back({startApprox[i] + edgeApprox[i][j], i, j});\n            }\n        }\n        sort(pairs.begin(), pairs.end(), [](const PairCand& x, const PairCand& y) {\n            if (x.approx != y.approx) return x.approx < y.approx;\n            if (x.a != y.a) return x.a < y.a;\n            return x.b < y.b;\n        });\n\n        int pairKeep = randomized ? 14 : 8;\n        pairKeep = min<int>(pairKeep, pairs.size());\n\n        int bestPairExact = INF;\n        vector<pair<int, pair<int, int>>> exactPairs;\n        for (int t = 0; t < pairKeep; t++) {\n            vector<int> p = {pairs[t].a, pairs[t].b};\n            int ex = evalPerm(p);\n            exactPairs.push_back({ex, {pairs[t].a, pairs[t].b}});\n            if (ex < bestPairExact) bestPairExact = ex;\n        }\n        sort(exactPairs.begin(), exactPairs.end());\n\n        int choosePair = 0;\n        if (randomized) {\n            int lim = min<int>(3, exactPairs.size());\n            choosePair = uniform_int_distribution<int>(0, lim - 1)(rr);\n        }\n\n        vector<int> perm = {exactPairs[choosePair].second.first, exactPairs[choosePair].second.second};\n        vector<char> used(M, 0);\n        used[perm[0]] = used[perm[1]] = 1;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                int inc;\n                int x, pos;\n            };\n            vector<Cand> global;\n            int keepPerX = randomized ? 2 : 1;\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                vector<Cand> bests;\n                bests.reserve(keepPerX + 2);\n\n                auto push = [&](Cand c) {\n                    bests.push_back(c);\n                    sort(bests.begin(), bests.end(), [](const Cand& a, const Cand& b) {\n                        if (a.inc != b.inc) return a.inc < b.inc;\n                        if (a.x != b.x) return a.x < b.x;\n                        return a.pos < b.pos;\n                    });\n                    if ((int)bests.size() > keepPerX) bests.pop_back();\n                };\n\n                push({startApprox[x] + edgeApprox[x][perm[0]] - startApprox[perm[0]], x, 0});\n                for (int i = 1; i < (int)perm.size(); i++) {\n                    int inc = edgeApprox[perm[i - 1]][x] + edgeApprox[x][perm[i]] - edgeApprox[perm[i - 1]][perm[i]];\n                    push({inc, x, i});\n                }\n                push({edgeApprox[perm.back()][x], x, (int)perm.size()});\n\n                for (auto& c : bests) global.push_back(c);\n            }\n\n            sort(global.begin(), global.end(), [](const Cand& a, const Cand& b) {\n                if (a.inc != b.inc) return a.inc < b.inc;\n                if (a.x != b.x) return a.x < b.x;\n                return a.pos < b.pos;\n            });\n\n            int globalKeep = randomized ? 14 : 8;\n            globalKeep = min<int>(globalKeep, global.size());\n\n            int bestExact = INF;\n            vector<Cand> exactBest;\n            for (int t = 0; t < globalKeep; t++) {\n                auto c = global[t];\n                vector<int> np = perm;\n                np.insert(np.begin() + c.pos, c.x);\n                int ex = evalPerm(np);\n                if (ex < bestExact) bestExact = ex;\n                exactBest.push_back(c);\n                exactBest.back().inc = ex;\n            }\n\n            sort(exactBest.begin(), exactBest.end(), [](const Cand& a, const Cand& b) {\n                if (a.inc != b.inc) return a.inc < b.inc;\n                if (a.x != b.x) return a.x < b.x;\n                return a.pos < b.pos;\n            });\n\n            int choose = 0;\n            if (randomized) {\n                int lim = min<int>(2, exactBest.size());\n                choose = uniform_int_distribution<int>(0, lim - 1)(rr);\n            }\n\n            auto c = exactBest[choose];\n            perm.insert(perm.begin() + c.pos, c.x);\n            used[c.x] = 1;\n        }\n\n        return perm;\n    }\n\n    // ---------- Approx deltas for local search ----------\n\n    inline long long linkApprox(int prev, int cur) const {\n        if (cur == -1) return 0;\n        if (prev == -1) return startApprox[cur];\n        return edgeApprox[prev][cur];\n    }\n\n    long long blockRelocateDelta(const vector<int>& p, int a, int len, int b) const {\n        int n = (int)p.size();\n        int x0 = p[a];\n        int x1 = p[a + len - 1];\n        int A = (a > 0 ? p[a - 1] : -1);\n        int B = (a + len < n ? p[a + len] : -1);\n\n        auto qAt = [&](int idx) -> int {\n            if (idx < a) return p[idx];\n            return p[idx + len];\n        };\n\n        int qSize = n - len;\n        int C = (b > 0 ? qAt(b - 1) : -1);\n        int D = (b < qSize ? qAt(b) : -1);\n\n        long long delta = 0;\n        delta -= linkApprox(A, x0);\n        delta -= linkApprox(x1, B);\n        delta += linkApprox(A, B);\n\n        delta -= linkApprox(C, D);\n        delta += linkApprox(C, x0);\n        delta += linkApprox(x1, D);\n\n        return delta;\n    }\n\n    long long swapDelta(const vector<int>& p, int a, int b) const {\n        if (a == b) return 0;\n        if (a > b) swap(a, b);\n        int n = (int)p.size();\n\n        int A = p[a], B = p[b];\n        int pA = (a > 0 ? p[a - 1] : -1);\n        int nA = (a + 1 < n ? p[a + 1] : -1);\n        int pB = (b > 0 ? p[b - 1] : -1);\n        int nB = (b + 1 < n ? p[b + 1] : -1);\n\n        long long oldCost = 0, newCost = 0;\n\n        if (a + 1 == b) {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, A);\n            newCost += linkApprox(A, nB);\n        } else {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, nA);\n            oldCost += linkApprox(pB, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, nA);\n            newCost += linkApprox(pB, A);\n            newCost += linkApprox(A, nB);\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyBlockRelocate(vector<int>& p, int a, int len, int b) const {\n        vector<int> block(p.begin() + a, p.begin() + a + len);\n        p.erase(p.begin() + a, p.begin() + a + len);\n        p.insert(p.begin() + b, block.begin(), block.end());\n    }\n\n    void applyMove(vector<int>& p, int type, int a, int b) const {\n        // type 0: relocate len 1\n        // type 1: relocate len 2\n        // type 2: swap\n        if (type == 0) applyBlockRelocate(p, a, 1, b);\n        else if (type == 1) applyBlockRelocate(p, a, 2, b);\n        else swap(p[a], p[b]);\n    }\n\n    struct MoveCand {\n        long long d;\n        int type, a, b;\n    };\n\n    pair<vector<int>, int> localSearch(vector<int> perm, int curExact, int maxIter, int topK) {\n        int n = (int)perm.size();\n\n        for (int iter = 0; iter < maxIter && !timeup(0.06); iter++) {\n            vector<MoveCand> cand;\n            cand.reserve(n * n + max(0, (n - 1) * (n - 1)) + n * (n - 1) / 2);\n\n            // relocate len 1\n            for (int a = 0; a < n; a++) {\n                for (int b = 0; b <= n - 1; b++) {\n                    if (b == a) continue; // same place\n                    long long d = blockRelocateDelta(perm, a, 1, b);\n                    cand.push_back({d, 0, a, b});\n                }\n            }\n\n            // relocate len 2\n            if (n >= 2) {\n                for (int a = 0; a + 1 < n; a++) {\n                    for (int b = 0; b <= n - 2; b++) {\n                        if (b == a) continue; // same place\n                        long long d = blockRelocateDelta(perm, a, 2, b);\n                        cand.push_back({d, 1, a, b});\n                    }\n                }\n            }\n\n            // swap\n            for (int a = 0; a < n; a++) {\n                for (int b = a + 1; b < n; b++) {\n                    long long d = swapDelta(perm, a, b);\n                    cand.push_back({d, 2, a, b});\n                }\n            }\n\n            auto comp = [](const MoveCand& x, const MoveCand& y) {\n                if (x.d != y.d) return x.d < y.d;\n                if (x.type != y.type) return x.type < y.type;\n                if (x.a != y.a) return x.a < y.a;\n                return x.b < y.b;\n            };\n\n            int K = min<int>(topK, cand.size());\n            if (K == 0) break;\n            if (K < (int)cand.size()) {\n                nth_element(cand.begin(), cand.begin() + K, cand.end(), comp);\n                cand.resize(K);\n            }\n            sort(cand.begin(), cand.end(), comp);\n\n            bool improved = false;\n            int bestExact = curExact;\n            vector<int> bestPerm;\n\n            for (auto& mv : cand) {\n                if (timeup(0.05)) break;\n                vector<int> np = perm;\n                applyMove(np, mv.type, mv.a, mv.b);\n                int ex = evalPerm(np);\n                if (ex < bestExact) {\n                    bestExact = ex;\n                    bestPerm.swap(np);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            perm.swap(bestPerm);\n            curExact = bestExact;\n        }\n\n        return {perm, curExact};\n    }\n\n    void randomKick(vector<int>& perm, mt19937& rr, int cnt) const {\n        int n = (int)perm.size();\n        for (int t = 0; t < cnt; t++) {\n            int typ = uniform_int_distribution<int>(0, 2)(rr);\n            if (typ == 0) {\n                int a = uniform_int_distribution<int>(0, n - 1)(rr);\n                int b = uniform_int_distribution<int>(0, n - 1)(rr);\n                if (a != b) swap(perm[a], perm[b]);\n            } else if (typ == 1) {\n                int a = uniform_int_distribution<int>(0, n - 1)(rr);\n                int b = uniform_int_distribution<int>(0, n - 1)(rr);\n                applyBlockRelocate(perm, a, 1, b);\n            } else {\n                if (n >= 2) {\n                    int a = uniform_int_distribution<int>(0, n - 2)(rr);\n                    int b = uniform_int_distribution<int>(0, n - 2)(rr);\n                    applyBlockRelocate(perm, a, 2, b);\n                }\n            }\n        }\n    }\n\n    pair<int, vector<int>> exactPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n\n        const auto& firstPos = occ[s[0] - 'A'];\n        vector<int> dpPrev(firstPos.size());\n        parent[0].assign(firstPos.size(), -1);\n        for (int i = 0; i < (int)firstPos.size(); i++) {\n            dpPrev[i] = man[startPos][firstPos[i]] + 1;\n        }\n\n        for (int t = 1; t < L; t++) {\n            const auto& prevPos = occ[s[t - 1] - 'A'];\n            const auto& curPos = occ[s[t] - 'A'];\n            vector<int> dpCur(curPos.size(), INF);\n            parent[t].assign(curPos.size(), -1);\n\n            for (int ci = 0; ci < (int)curPos.size(); ci++) {\n                int q = curPos[ci];\n                int best = INF, bestp = -1;\n                for (int pi = 0; pi < (int)prevPos.size(); pi++) {\n                    int cand = dpPrev[pi] + man[prevPos[pi]][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bestp = pi;\n                    }\n                }\n                dpCur[ci] = best;\n                parent[t][ci] = bestp;\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        int best = INF, idx = -1;\n        for (int i = 0; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < best) {\n                best = dpPrev[i];\n                idx = i;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = occ[s[L - 1] - 'A'][idx];\n        for (int t = L - 1; t >= 1; t--) {\n            idx = parent[t][idx];\n            path[t - 1] = occ[s[t - 1] - 'A'][idx];\n        }\n        return {best, path};\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        readInput();\n        buildSeed();\n        precomputeKeyboard();\n        precomputeOverlaps();\n        precomputeMatrices();\n\n        vector<int> startOrder(M);\n        iota(startOrder.begin(), startOrder.end(), 0);\n        sort(startOrder.begin(), startOrder.end(), [&](int a, int b) {\n            if (startApprox[a] != startApprox[b]) return startApprox[a] < startApprox[b];\n            return a < b;\n        });\n\n        struct SeedCand {\n            vector<int> perm;\n            int exact;\n        };\n        vector<SeedCand> seeds;\n\n        auto addSeed = [&](vector<int> p) {\n            int ex = evalPerm(p);\n            seeds.push_back({move(p), ex});\n        };\n\n        // Exact greedy append from good starts\n        addSeed(initGreedyAppend(startOrder[0], baseSeed + 11, false));\n        if (M >= 2) addSeed(initGreedyAppend(startOrder[1], baseSeed + 12, false));\n        if (M >= 3) addSeed(initGreedyAppend(startOrder[2], baseSeed + 13, false));\n\n        {\n            mt19937 rr(baseSeed + 100);\n            int lim = min(10, M);\n            for (int z = 0; z < 4 && !timeup(0.55); z++) {\n                int first = startOrder[uniform_int_distribution<int>(0, lim - 1)(rr)];\n                addSeed(initGreedyAppend(first, baseSeed + 21 + z, true));\n            }\n        }\n\n        // New: exact-informed insertion seeds\n        if (!timeup(0.45)) addSeed(initExactInsertion(baseSeed + 31, false));\n        if (!timeup(0.45)) addSeed(initExactInsertion(baseSeed + 32, true));\n\n        // Complementary seed\n        if (!timeup(0.40)) addSeed(initEdgeGreedy(baseSeed + 41, false));\n        if (!timeup(0.40)) addSeed(initEdgeGreedy(baseSeed + 42, true));\n\n        sort(seeds.begin(), seeds.end(), [](const SeedCand& a, const SeedCand& b) {\n            return a.exact < b.exact;\n        });\n\n        vector<int> bestPerm = seeds[0].perm;\n        int bestExact = seeds[0].exact;\n\n        int topSeedCnt = min<int>(4, seeds.size());\n        for (int i = 0; i < topSeedCnt && !timeup(0.22); i++) {\n            int K = (elapsed() < 1.05 ? 2400 : 1700);\n            auto cur = localSearch(seeds[i].perm, seeds[i].exact, 7, K);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        // Iterated local search\n        mt19937 rr(baseSeed + 999);\n        int noImprove = 0;\n        while (!timeup(0.09)) {\n            vector<int> p = bestPerm;\n            int kickCnt = (noImprove < 3 ? 2 : 4);\n            randomKick(p, rr, kickCnt);\n            int ex = evalPerm(p);\n\n            int K = (elapsed() < 1.45 ? 1300 : 800);\n            auto cur = localSearch(move(p), ex, 4, K);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n                noImprove = 0;\n            } else {\n                noImprove++;\n                if (noImprove >= 7 && elapsed() > 1.58) break;\n            }\n        }\n\n        string finalS = buildString(bestPerm);\n        auto [finalCost, path] = exactPathForString(finalS);\n\n        for (int pos : path) {\n            cout << (pos / N) << ' ' << (pos % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXQ = 160;\nstatic constexpr int WORDS = 7; // 7*64 = 448 >= 400\n\nusing ull = unsigned long long;\nusing Mask = array<ull, WORDS>;\n\nstruct Placement {\n    int di = 0, dj = 0;\n    Mask mask{};\n    array<unsigned char, MAXQ> contrib{};\n};\n\nstruct Field {\n    int sz = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> pls;\n};\n\nstruct State {\n    vector<int> choice;\n    array<short, MAXQ> setsum{};\n    vector<short> drillsum;\n    int pen = 0;\n    double div = 0.0;\n};\n\nstruct WeightedStates {\n    bool plausible = false;\n    int bestPen = INT_MAX;\n    vector<int> idx;\n    vector<double> w;\n    double sumW = 0.0;\n};\n\nstruct UnionSummary {\n    bool hasPlausible = false;\n    int bestPen = INT_MAX;\n    int distinctUnionCount = 0;\n\n    vector<Mask> masks;\n    vector<double> weights;\n\n    Mask bestMask{};\n    Mask must1{};\n    Mask maybe1{};\n\n    double bestWeight = 0.0;\n\n    vector<int> ambiguous;\n\n    vector<double> supportProb;\n    vector<double> supportVar;\n    vector<double> countVar;\n\n    double maxCellScore = -1.0;\n    int bestCell = -1;\n};\n\nstruct Solver {\n    int N, M, NN;\n    double eps, alpha;\n    int totalArea = 0;\n    int maxOps, ops = 0;\n\n    vector<Field> fields;\n\n    int Qcur = 0;\n    vector<vector<int>> queryCells;\n    vector<Mask> queryMasks;\n    vector<int> qSize, qResp;\n    vector<char> qKnown;\n    vector<vector<double>> qScore; // negative log-likelihood\n\n    vector<array<int,4>> cellQids; // row, col, mod2, mod3\n\n    vector<int> drilledCells, drilledObs;\n    vector<int> cellObs;\n    vector<char> drilledFlag;\n\n    vector<State> pool;\n\n    vector<Mask> rowParityMask, colParityMask, checkerMask, rowMod3Mask, colMod3Mask;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point stTime;\n    double compLog2 = 0.0;\n    int adaptiveQueriesUsed = 0;\n\n    Solver(): rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    // ---------- mask helpers ----------\n    static inline void mask_clear(Mask &m) { m.fill(0); }\n    static inline void mask_set(Mask &m, int idx) { m[idx >> 6] |= (1ULL << (idx & 63)); }\n    static inline bool mask_test(const Mask &m, int idx) { return (m[idx >> 6] >> (idx & 63)) & 1ULL; }\n    static inline void mask_or_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] |= b[i]; }\n    static inline void mask_and_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] &= b[i]; }\n    static inline Mask mask_or(const Mask &a, const Mask &b) { Mask c = a; mask_or_eq(c, b); return c; }\n    static inline Mask mask_and(const Mask &a, const Mask &b) { Mask c = a; mask_and_eq(c, b); return c; }\n    static inline Mask mask_xor(const Mask &a, const Mask &b) {\n        Mask c{};\n        for (int i = 0; i < WORDS; i++) c[i] = a[i] ^ b[i];\n        return c;\n    }\n    static inline Mask mask_andnot(const Mask &a, const Mask &b) {\n        Mask c{};\n        for (int i = 0; i < WORDS; i++) c[i] = a[i] & ~b[i];\n        return c;\n    }\n    static inline int mask_popcount(const Mask &m) {\n        int s = 0;\n        for (int i = 0; i < WORDS; i++) s += __builtin_popcountll(m[i]);\n        return s;\n    }\n    static inline bool mask_empty(const Mask &m) {\n        for (int i = 0; i < WORDS; i++) if (m[i]) return false;\n        return true;\n    }\n    static inline int intersect_count(const Mask &a, const Mask &b) {\n        int s = 0;\n        for (int i = 0; i < WORDS; i++) s += __builtin_popcountll(a[i] & b[i]);\n        return s;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - stTime).count();\n    }\n\n    bool better(int p1, double d1, int p2, double d2) const {\n        if (p1 != p2) return p1 < p2;\n        return d1 + 1e-12 < d2;\n    }\n\n    int rand_int(int lim) {\n        return int(rng() % (uint64_t)lim);\n    }\n\n    int activeQCount() const {\n        int c = 0;\n        for (int q = 0; q < Qcur; q++) c += qKnown[q];\n        return c;\n    }\n\n    bool can_spend_ops(int extraOps) const {\n        int needFallback = (NN - (int)drilledCells.size()) + 1; // remaining drills + final answer\n        return ops + extraOps + needFallback <= maxOps;\n    }\n\n    vector<int> cells_from_mask(const Mask &m) const {\n        vector<int> cells;\n        cells.reserve(mask_popcount(m));\n        for (int idx = 0; idx < NN; idx++) if (mask_test(m, idx)) cells.push_back(idx);\n        return cells;\n    }\n\n    // ---------- probability ----------\n    static double norm_cdf(double x) {\n        static const double INV_SQRT2 = 0.707106781186547524400844362104849039;\n        return 0.5 * erfc(-x * INV_SQRT2);\n    }\n\n    static double rounded_normal_nll(int y, double mu, double sigma) {\n        double prob;\n        if (sigma < 1e-12) {\n            int z = max(0, (int)llround(mu));\n            prob = (z == y ? 1.0 : 0.0);\n        } else if (y == 0) {\n            double hi = (0.5 - mu) / sigma;\n            prob = norm_cdf(hi);\n        } else {\n            double lo = (y - 0.5 - mu) / sigma;\n            double hi = (y + 0.5 - mu) / sigma;\n            prob = norm_cdf(hi) - norm_cdf(lo);\n        }\n        if (prob < 1e-300) prob = 1e-300;\n        return -log(prob);\n    }\n\n    // ---------- I/O ----------\n    void read_input() {\n        cin >> N >> M >> eps;\n        NN = N * N;\n        maxOps = 2 * NN;\n        alpha = 1.0 - 2.0 * eps;\n\n        fields.resize(M);\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            fields[k].sz = d;\n            fields[k].rel.resize(d);\n            int mxr = 0, mxc = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].rel[t] = {i, j};\n                mxr = max(mxr, i);\n                mxc = max(mxc, j);\n            }\n            fields[k].h = mxr + 1;\n            fields[k].w = mxc + 1;\n            totalArea += d;\n        }\n\n        cellObs.assign(NN, -1);\n        drilledFlag.assign(NN, 0);\n\n        queryCells.assign(MAXQ, {});\n        queryMasks.assign(MAXQ, {});\n        qSize.assign(MAXQ, 0);\n        qResp.assign(MAXQ, 0);\n        qKnown.assign(MAXQ, 0);\n        qScore.assign(MAXQ, vector<double>(totalArea + 1, 0.0));\n    }\n\n    int ask_set_query(const vector<int> &cells) {\n        cout << \"q \" << cells.size();\n        for (int idx : cells) cout << ' ' << (idx / N) << ' ' << (idx % N);\n        cout << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << ' ' << (idx % N) << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    bool answer_mask(const Mask &mask) {\n        vector<int> cells;\n        cells.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) if (mask_test(mask, idx)) cells.push_back(idx);\n\n        cout << \"a \" << cells.size();\n        for (int idx : cells) cout << ' ' << (idx / N) << ' ' << (idx % N);\n        cout << '\\n' << flush;\n        int res;\n        cin >> res;\n        ops++;\n        return res == 1;\n    }\n\n    // ---------- setup ----------\n    void build_queries() {\n        // base queries:\n        // [0, N) row\n        // [N, 2N) col\n        // [2N, 2N+4) mod2\n        // [2N+4, 2N+13) mod3\n        Qcur = 2 * N + 13;\n        cellQids.resize(NN);\n\n        rowParityMask.assign(2, Mask{});\n        colParityMask.assign(2, Mask{});\n        checkerMask.assign(2, Mask{});\n        rowMod3Mask.assign(3, Mask{});\n        colMod3Mask.assign(3, Mask{});\n        for (auto &m : rowParityMask) mask_clear(m);\n        for (auto &m : colParityMask) mask_clear(m);\n        for (auto &m : checkerMask) mask_clear(m);\n        for (auto &m : rowMod3Mask) mask_clear(m);\n        for (auto &m : colMod3Mask) mask_clear(m);\n\n        for (int q = 0; q < Qcur; q++) {\n            queryCells[q].clear();\n            mask_clear(queryMasks[q]);\n        }\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int idx = i * N + j;\n                int q0 = i;\n                int q1 = N + j;\n                int q2 = 2 * N + (i & 1) * 2 + (j & 1);\n                int q3 = 2 * N + 4 + (i % 3) * 3 + (j % 3);\n                cellQids[idx] = {q0, q1, q2, q3};\n\n                queryCells[q0].push_back(idx);\n                queryCells[q1].push_back(idx);\n                queryCells[q2].push_back(idx);\n                queryCells[q3].push_back(idx);\n\n                mask_set(rowParityMask[i & 1], idx);\n                mask_set(colParityMask[j & 1], idx);\n                mask_set(checkerMask[(i + j) & 1], idx);\n                mask_set(rowMod3Mask[i % 3], idx);\n                mask_set(colMod3Mask[j % 3], idx);\n            }\n        }\n\n        for (int q = 0; q < Qcur; q++) {\n            for (int idx : queryCells[q]) mask_set(queryMasks[q], idx);\n            qSize[q] = (int)queryCells[q].size();\n        }\n    }\n\n    void precompute_placements() {\n        compLog2 = 0.0;\n        for (int k = 0; k < M; k++) {\n            auto &f = fields[k];\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                    mask_clear(p.mask);\n                    p.contrib.fill(0);\n\n                    for (auto [ri, rj] : f.rel) {\n                        int ai = di + ri;\n                        int aj = dj + rj;\n                        int idx = ai * N + aj;\n                        mask_set(p.mask, idx);\n                        auto &arr = cellQids[idx];\n                        for (int t = 0; t < 4; t++) p.contrib[arr[t]]++;\n                    }\n                    f.pls.push_back(p);\n                }\n            }\n            compLog2 += log2((double)max(1, (int)f.pls.size()));\n        }\n    }\n\n    void register_query_response(int q, int y) {\n        qKnown[q] = 1;\n        qResp[q] = y;\n\n        double sigma = sqrt((double)qSize[q] * eps * (1.0 - eps));\n        for (int v = 0; v <= totalArea; v++) {\n            double mu = eps * qSize[q] + alpha * v;\n            qScore[q][v] = rounded_normal_nll(y, mu, sigma);\n        }\n    }\n\n    void activate_queries(int l, int r) {\n        for (int q = l; q < r; q++) {\n            if (qKnown[q]) continue;\n            if (!can_spend_ops(1)) return;\n            int y = ask_set_query(queryCells[q]);\n            register_query_response(q, y);\n        }\n    }\n\n    bool add_adaptive_query(const Mask &m) {\n        int k = mask_popcount(m);\n        if (k < 2 || Qcur >= MAXQ) return false;\n        if (!can_spend_ops(1)) return false;\n        for (int q = 0; q < Qcur; q++) {\n            if (queryMasks[q] == m) return false;\n        }\n\n        int q = Qcur++;\n        queryMasks[q] = m;\n        queryCells[q] = cells_from_mask(m);\n        qSize[q] = k;\n\n        for (auto &f : fields) {\n            for (auto &pl : f.pls) {\n                pl.contrib[q] = (unsigned char)intersect_count(pl.mask, m);\n            }\n        }\n\n        int y = ask_set_query(queryCells[q]);\n        register_query_response(q, y);\n        adaptiveQueriesUsed++;\n        return true;\n    }\n\n    // ---------- state build / local search ----------\n    State build_state(const vector<int> &choice) {\n        State st;\n        st.choice = choice;\n        st.setsum.fill(0);\n\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[choice[k]];\n            for (int q = 0; q < Qcur; q++) st.setsum[q] += pl.contrib[q];\n        }\n\n        st.div = 0.0;\n        for (int q = 0; q < Qcur; q++) if (qKnown[q]) st.div += qScore[q][st.setsum[q]];\n\n        int D = (int)drilledCells.size();\n        st.drillsum.assign(D, 0);\n        st.pen = 0;\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int s = 0;\n            for (int k = 0; k < M; k++) {\n                s += (int)mask_test(fields[k].pls[choice[k]].mask, idx);\n            }\n            st.drillsum[t] = (short)s;\n            int d = s - drilledObs[t];\n            st.pen += d * d;\n        }\n        return st;\n    }\n\n    void apply_move(State &st, int k, int newPid) {\n        int oldPid = st.choice[k];\n        if (oldPid == newPid) return;\n\n        const auto &oldPl = fields[k].pls[oldPid];\n        const auto &newPl = fields[k].pls[newPid];\n\n        for (int q = 0; q < Qcur; q++) {\n            int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n            if (!diff) continue;\n            int oldv = st.setsum[q];\n            int newv = oldv + diff;\n            if (qKnown[q]) st.div += qScore[q][newv] - qScore[q][oldv];\n            st.setsum[q] = (short)newv;\n        }\n\n        int D = (int)drilledCells.size();\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n            if (!diff) continue;\n            int oldv = st.drillsum[t];\n            int newv = oldv + diff;\n            int before = oldv - drilledObs[t];\n            int after = newv - drilledObs[t];\n            st.pen += after * after - before * before;\n            st.drillsum[t] = (short)newv;\n        }\n\n        st.choice[k] = newPid;\n    }\n\n    void hill_climb(State &st, int sweeps) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            bool changed = false;\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int z = 0; z < M; z++) {\n                int k = ord[z];\n                int oldPid = st.choice[k];\n                const auto &oldPl = fields[k].pls[oldPid];\n\n                int bestPid = oldPid;\n                int bestPen = st.pen;\n                double bestDiv = st.div;\n\n                int D = (int)drilledCells.size();\n\n                for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                    if (pid == oldPid) continue;\n                    const auto &newPl = fields[k].pls[pid];\n\n                    int candPen = st.pen;\n                    double candDiv = st.div;\n\n                    for (int q = 0; q < Qcur; q++) {\n                        int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n                        if (!diff) continue;\n                        int oldv = st.setsum[q];\n                        int newv = oldv + diff;\n                        if (qKnown[q]) candDiv += qScore[q][newv] - qScore[q][oldv];\n                    }\n\n                    for (int t = 0; t < D; t++) {\n                        int idx = drilledCells[t];\n                        int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n                        if (!diff) continue;\n                        int oldv = st.drillsum[t];\n                        int newv = oldv + diff;\n                        int before = oldv - drilledObs[t];\n                        int after = newv - drilledObs[t];\n                        candPen += after * after - before * before;\n                    }\n\n                    if (better(candPen, candDiv, bestPen, bestDiv)) {\n                        bestPen = candPen;\n                        bestDiv = candDiv;\n                        bestPid = pid;\n                    }\n                }\n\n                if (bestPid != oldPid) {\n                    apply_move(st, k, bestPid);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> random_seed() {\n        vector<int> choice(M);\n        for (int k = 0; k < M; k++) choice[k] = rand_int((int)fields[k].pls.size());\n        return choice;\n    }\n\n    vector<int> greedy_seed() {\n        vector<int> choice(M, 0);\n        array<short, MAXQ> cur{};\n        cur.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int id = 0; id < M; id++) {\n            int k = ord[id];\n            int bestPid = 0;\n            double bestDelta = 1e100;\n\n            for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                const auto &pl = fields[k].pls[pid];\n                double delta = 0.0;\n                for (int q = 0; q < Qcur; q++) {\n                    if (!qKnown[q]) continue;\n                    int c = pl.contrib[q];\n                    if (!c) continue;\n                    int oldv = cur[q];\n                    int newv = oldv + c;\n                    delta += qScore[q][newv] - qScore[q][oldv];\n                }\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPid = pid;\n                }\n            }\n\n            choice[k] = bestPid;\n            const auto &pl = fields[k].pls[bestPid];\n            for (int q = 0; q < Qcur; q++) cur[q] += pl.contrib[q];\n        }\n        return choice;\n    }\n\n    vector<int> perturbed_seed() {\n        if (pool.empty()) return random_seed();\n        int baseCnt = min(6, (int)pool.size());\n        vector<int> choice = pool[rand_int(baseCnt)].choice;\n\n        int changes = 1 + rand_int(max(1, min(5, M)));\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int t = 0; t < changes; t++) {\n            int k = ord[t];\n            int sz = (int)fields[k].pls.size();\n            if (sz <= 1) continue;\n            int cur = choice[k];\n            int np = rand_int(sz - 1);\n            if (np >= cur) np++;\n            choice[k] = np;\n        }\n        return choice;\n    }\n\n    bool contains_choice(const vector<vector<int>> &vv, const vector<int> &x) {\n        for (const auto &v : vv) if (v == x) return true;\n        return false;\n    }\n\n    void optimize_pool(int randomCnt, int pertCnt, int sweeps, bool useGreedy) {\n        vector<vector<int>> seeds;\n\n        for (const auto &st : pool) {\n            if (!contains_choice(seeds, st.choice)) seeds.push_back(st.choice);\n        }\n\n        if (useGreedy) {\n            int g = 6;\n            for (int t = 0; t < g; t++) {\n                auto s = greedy_seed();\n                if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n            }\n        }\n\n        for (int t = 0; t < pertCnt; t++) {\n            auto s = perturbed_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        for (int t = 0; t < randomCnt; t++) {\n            auto s = random_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        if (seeds.empty()) seeds.push_back(random_seed());\n\n        vector<State> cands;\n        cands.reserve(seeds.size());\n        for (auto &seed : seeds) {\n            State st = build_state(seed);\n            hill_climb(st, sweeps);\n            cands.push_back(move(st));\n        }\n\n        sort(cands.begin(), cands.end(), [&](const State &a, const State &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        pool.clear();\n        for (auto &st : cands) {\n            bool dup = false;\n            for (auto &kept : pool) {\n                if (kept.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) pool.push_back(move(st));\n            if ((int)pool.size() >= 28) break;\n        }\n    }\n\n    // ---------- drill bookkeeping ----------\n    void record_drill(int idx, int val) {\n        if (!drilledFlag[idx]) {\n            drilledFlag[idx] = 1;\n            cellObs[idx] = val;\n            drilledCells.push_back(idx);\n            drilledObs.push_back(val);\n        }\n    }\n\n    // ---------- summaries ----------\n    Mask union_of_choice(const vector<int> &choice) {\n        Mask u{};\n        mask_clear(u);\n        for (int k = 0; k < M; k++) mask_or_eq(u, fields[k].pls[choice[k]].mask);\n        return u;\n    }\n\n    vector<unsigned char> state_counts(const State &st) {\n        vector<unsigned char> cnt(NN, 0);\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[st.choice[k]];\n            for (auto [ri, rj] : fields[k].rel) {\n                int idx = (pl.di + ri) * N + (pl.dj + rj);\n                cnt[idx]++;\n            }\n        }\n        return cnt;\n    }\n\n    WeightedStates collect_weighted_states() {\n        WeightedStates ws;\n        if (pool.empty()) return ws;\n\n        ws.bestPen = pool[0].pen;\n        int aq = max(1, activeQCount());\n\n        if (ws.bestPen == 0) {\n            double bestDiv = 1e100;\n            for (const auto &st : pool) if (st.pen == 0) bestDiv = min(bestDiv, st.div);\n\n            double margin = 8.0 + 0.30 * aq;\n            for (int i = 0; i < (int)pool.size(); i++) {\n                if (pool[i].pen != 0) continue;\n                if (pool[i].div <= bestDiv + margin) {\n                    double w = exp(-min(50.0, (pool[i].div - bestDiv) / 2.5));\n                    ws.idx.push_back(i);\n                    ws.w.push_back(w);\n                    ws.sumW += w;\n                }\n            }\n            ws.plausible = !ws.idx.empty();\n        }\n\n        if (!ws.plausible) {\n            int take = min(14, (int)pool.size());\n            double base = 1e100;\n            vector<double> obj(take);\n            for (int i = 0; i < take; i++) {\n                obj[i] = pool[i].div + 20.0 * pool[i].pen;\n                base = min(base, obj[i]);\n            }\n            for (int i = 0; i < take; i++) {\n                double w = exp(-min(50.0, (obj[i] - base) / 4.0));\n                ws.idx.push_back(i);\n                ws.w.push_back(w);\n                ws.sumW += w;\n            }\n        }\n\n        if (ws.sumW <= 0.0) {\n            ws.sumW = (double)ws.w.size();\n            for (double &x : ws.w) x = 1.0;\n        }\n        return ws;\n    }\n\n    void compute_cell_stats(const WeightedStates &ws,\n                            vector<double> &supportProb,\n                            vector<double> &supportVar,\n                            vector<double> &countVar) {\n        supportProb.assign(NN, 0.0);\n        supportVar.assign(NN, 0.0);\n        countVar.assign(NN, 0.0);\n        if (ws.idx.empty()) return;\n\n        vector<double> meanCnt(NN, 0.0), sqCnt(NN, 0.0);\n\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            const State &st = pool[ws.idx[t]];\n            double w = ws.w[t];\n            vector<unsigned char> cnt = state_counts(st);\n\n            for (int idx = 0; idx < NN; idx++) {\n                double c = cnt[idx];\n                if (c > 0) supportProb[idx] += w;\n                meanCnt[idx] += w * c;\n                sqCnt[idx] += w * c * c;\n            }\n        }\n\n        for (int idx = 0; idx < NN; idx++) {\n            supportProb[idx] /= ws.sumW;\n            double p = supportProb[idx];\n            supportVar[idx] = p * (1.0 - p);\n\n            meanCnt[idx] /= ws.sumW;\n            sqCnt[idx] /= ws.sumW;\n            countVar[idx] = max(0.0, sqCnt[idx] - meanCnt[idx] * meanCnt[idx]);\n        }\n    }\n\n    UnionSummary summarize_unions() {\n        UnionSummary us;\n        if (pool.empty()) return us;\n\n        WeightedStates ws = collect_weighted_states();\n        us.hasPlausible = ws.plausible;\n        us.bestPen = ws.bestPen;\n        if (ws.idx.empty()) return us;\n\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            Mask u = union_of_choice(pool[ws.idx[t]].choice);\n            double w = ws.w[t];\n            int pos = -1;\n            for (int i = 0; i < (int)us.masks.size(); i++) {\n                if (us.masks[i] == u) {\n                    pos = i;\n                    break;\n                }\n            }\n            if (pos == -1) {\n                us.masks.push_back(u);\n                us.weights.push_back(w);\n            } else {\n                us.weights[pos] += w;\n            }\n        }\n\n        us.distinctUnionCount = (int)us.masks.size();\n        if (us.masks.empty()) return us;\n\n        double sumW = 0.0;\n        for (double w : us.weights) sumW += w;\n        if (sumW <= 0.0) {\n            sumW = (double)us.weights.size();\n            for (double &w : us.weights) w = 1.0;\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)us.weights.size(); i++) {\n            if (us.weights[i] > us.weights[bestIdx]) bestIdx = i;\n        }\n        us.bestMask = us.masks[bestIdx];\n        us.bestWeight = us.weights[bestIdx] / sumW;\n\n        if (us.hasPlausible) {\n            us.must1 = us.masks[0];\n            us.maybe1 = us.masks[0];\n            for (int i = 1; i < (int)us.masks.size(); i++) {\n                mask_and_eq(us.must1, us.masks[i]);\n                mask_or_eq(us.maybe1, us.masks[i]);\n            }\n            Mask amb = mask_xor(us.must1, us.maybe1);\n            for (int idx = 0; idx < NN; idx++) if (mask_test(amb, idx)) us.ambiguous.push_back(idx);\n        }\n\n        compute_cell_stats(ws, us.supportProb, us.supportVar, us.countVar);\n\n        us.maxCellScore = -1.0;\n        us.bestCell = -1;\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            for (int idx : us.ambiguous) {\n                if (drilledFlag[idx]) continue;\n                double sc = us.supportVar[idx] + 0.15 * min(1.0, us.countVar[idx]);\n                if (sc > us.maxCellScore + 1e-15) {\n                    us.maxCellScore = sc;\n                    us.bestCell = idx;\n                }\n            }\n        }\n\n        if (us.bestCell == -1) {\n            for (int idx = 0; idx < NN; idx++) {\n                if (drilledFlag[idx]) continue;\n                double sc = 0.8 * us.supportVar[idx] + 0.2 * min(1.0, us.countVar[idx]);\n                if (sc > us.maxCellScore + 1e-15) {\n                    us.maxCellScore = sc;\n                    us.bestCell = idx;\n                }\n            }\n        }\n\n        return us;\n    }\n\n    // ---------- answering / fallback ----------\n    Mask consensus_answer_mask(const UnionSummary &us) {\n        Mask ans = us.must1;\n        for (int idx = 0; idx < NN; idx++) if (cellObs[idx] > 0) mask_set(ans, idx);\n        return ans;\n    }\n\n    bool try_answer_strong(double weightThreshold, bool allowLowVar) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n\n        bool ok = false;\n        if (us.distinctUnionCount == 1) ok = true;\n        else if (us.bestWeight >= weightThreshold) ok = true;\n        else if (allowLowVar && us.bestWeight >= 0.90 && us.maxCellScore >= 0.0 && us.maxCellScore < 0.01) ok = true;\n\n        if (!ok) return false;\n        return answer_mask(us.bestMask);\n    }\n\n    bool speculative_guess() {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (pool.empty() || pool[0].pen != 0) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n\n        bool go = false;\n        if (us.bestWeight >= 0.82) go = true;\n        if (us.distinctUnionCount <= 3 && need <= 14) go = true;\n        if (!go) return false;\n\n        return answer_mask(us.bestMask);\n    }\n\n    void full_drill_and_answer() {\n        for (int idx = 0; idx < NN; idx++) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n        Mask ans{};\n        mask_clear(ans);\n        for (int idx = 0; idx < NN; idx++) if (cellObs[idx] > 0) mask_set(ans, idx);\n        answer_mask(ans);\n    }\n\n    bool try_small_ambiguous_finish(int limitUndrilled) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (pool.empty() || pool[0].pen != 0) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n        if (need == 0) {\n            if (!us.ambiguous.empty()) return false;\n            Mask ans = consensus_answer_mask(us);\n            return answer_mask(ans);\n        }\n\n        if (need > limitUndrilled) return false;\n        if (ops + need + 1 > maxOps) return false;\n\n        for (int idx : us.ambiguous) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n\n        if (elapsed() < 2.45) optimize_pool(4, 10, 4, false);\n\n        auto us2 = summarize_unions();\n        if (!us2.hasPlausible) return false;\n        if (pool.empty() || pool[0].pen != 0) return false;\n        if (!us2.ambiguous.empty()) return false;\n\n        Mask ans = consensus_answer_mask(us2);\n        return answer_mask(ans);\n    }\n\n    // ---------- adaptive discriminative queries ----------\n    int predicted_sum_on_mask(const State &st, const Mask &m) {\n        int s = 0;\n        for (int k = 0; k < M; k++) {\n            s += intersect_count(fields[k].pls[st.choice[k]].mask, m);\n        }\n        return s;\n    }\n\n    double evaluate_candidate_query(const Mask &m, const WeightedStates &ws) {\n        int k = mask_popcount(m);\n        if (k < 2 || ws.idx.empty()) return -1e100;\n\n        double mean = 0.0, sq = 0.0;\n        int mn = INT_MAX, mx = INT_MIN;\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            int pred = predicted_sum_on_mask(pool[ws.idx[t]], m);\n            mn = min(mn, pred);\n            mx = max(mx, pred);\n            double w = ws.w[t] / ws.sumW;\n            mean += w * pred;\n            sq += w * pred * pred;\n        }\n        if (mx == mn) return -1e100;\n\n        double varState = max(0.0, sq - mean * mean);\n        double noise = k * eps * (1.0 - eps) + 0.25;\n        return (varState / (noise + 1e-9)) * sqrt((double)k);\n    }\n\n    void add_candidate_mask(vector<Mask> &cand, const Mask &m) {\n        int k = mask_popcount(m);\n        if (k < 2) return;\n        for (const auto &x : cand) if (x == m) return;\n        for (int q = 0; q < Qcur; q++) if (queryMasks[q] == m) return;\n        cand.push_back(m);\n    }\n\n    vector<Mask> generate_candidate_masks(const UnionSummary &us, const WeightedStates &ws) {\n        vector<Mask> cand;\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            Mask amb = mask_xor(us.must1, us.maybe1);\n            add_candidate_mask(cand, amb);\n\n            add_candidate_mask(cand, mask_and(amb, rowParityMask[0]));\n            add_candidate_mask(cand, mask_and(amb, rowParityMask[1]));\n            add_candidate_mask(cand, mask_and(amb, colParityMask[0]));\n            add_candidate_mask(cand, mask_and(amb, colParityMask[1]));\n            add_candidate_mask(cand, mask_and(amb, checkerMask[0]));\n            add_candidate_mask(cand, mask_and(amb, checkerMask[1]));\n\n            if (mask_popcount(amb) >= 10) {\n                for (int r = 0; r < 3; r++) add_candidate_mask(cand, mask_and(amb, rowMod3Mask[r]));\n                for (int c = 0; c < 3; c++) add_candidate_mask(cand, mask_and(amb, colMod3Mask[c]));\n            }\n        }\n\n        if (us.masks.size() >= 2) {\n            int b1 = 0, b2 = -1;\n            for (int i = 1; i < (int)us.weights.size(); i++) {\n                if (us.weights[i] > us.weights[b1]) {\n                    b2 = b1;\n                    b1 = i;\n                } else if (b2 == -1 || us.weights[i] > us.weights[b2]) {\n                    b2 = i;\n                }\n            }\n            if (b2 != -1) {\n                add_candidate_mask(cand, mask_xor(us.masks[b1], us.masks[b2]));\n                add_candidate_mask(cand, mask_andnot(us.masks[b1], us.masks[b2]));\n                add_candidate_mask(cand, mask_andnot(us.masks[b2], us.masks[b1]));\n            }\n        }\n\n        // Top uncertain cells\n        vector<int> ord;\n        ord.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) if (!drilledFlag[idx]) ord.push_back(idx);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (us.supportVar[a] != us.supportVar[b]) return us.supportVar[a] > us.supportVar[b];\n            return us.countVar[a] > us.countVar[b];\n        });\n        int take = min((int)ord.size(), max(10, min(56, 2 * N + 8)));\n        Mask topU{};\n        mask_clear(topU);\n        for (int i = 0; i < take; i++) mask_set(topU, ord[i]);\n        add_candidate_mask(cand, topU);\n        add_candidate_mask(cand, mask_and(topU, checkerMask[0]));\n        add_candidate_mask(cand, mask_and(topU, checkerMask[1]));\n        add_candidate_mask(cand, mask_and(topU, rowParityMask[0]));\n        add_candidate_mask(cand, mask_and(topU, rowParityMask[1]));\n\n        for (int rep = 0; rep < 3; rep++) {\n            Mask h{};\n            mask_clear(h);\n            for (int i = 0; i < take; i++) {\n                int idx = ord[i];\n                ull z = (ull)(idx + 1) * 11995408973635179863ULL + (ull)(rep + 7) * 10150724397891781847ULL;\n                if ((z >> 63) & 1ULL) mask_set(h, idx);\n            }\n            add_candidate_mask(cand, h);\n            Mask hc = mask_andnot(topU, h);\n            add_candidate_mask(cand, hc);\n        }\n\n        // Pairwise count-difference masks on top candidate states\n        vector<int> rank(ws.idx.size());\n        iota(rank.begin(), rank.end(), 0);\n        sort(rank.begin(), rank.end(), [&](int a, int b) { return ws.w[a] > ws.w[b]; });\n        int T = min(6, (int)rank.size());\n\n        vector<vector<unsigned char>> cnts;\n        vector<int> sids;\n        for (int t = 0; t < T; t++) {\n            int si = ws.idx[rank[t]];\n            sids.push_back(si);\n            cnts.push_back(state_counts(pool[si]));\n        }\n\n        for (int a = 0; a < T; a++) {\n            for (int b = a + 1; b < T; b++) {\n                Mask gt{}, lt{}, sdiff{}, bigdiff{};\n                mask_clear(gt); mask_clear(lt); mask_clear(sdiff); mask_clear(bigdiff);\n                for (int idx = 0; idx < NN; idx++) {\n                    int ca = cnts[a][idx];\n                    int cb = cnts[b][idx];\n                    if (ca > cb) mask_set(gt, idx);\n                    if (ca < cb) mask_set(lt, idx);\n                    if ((ca > 0) != (cb > 0)) mask_set(sdiff, idx);\n                    if (abs(ca - cb) >= 2) mask_set(bigdiff, idx);\n                }\n                add_candidate_mask(cand, gt);\n                add_candidate_mask(cand, lt);\n                add_candidate_mask(cand, sdiff);\n                add_candidate_mask(cand, bigdiff);\n\n                add_candidate_mask(cand, mask_and(gt, checkerMask[0]));\n                add_candidate_mask(cand, mask_and(gt, checkerMask[1]));\n                add_candidate_mask(cand, mask_and(lt, checkerMask[0]));\n                add_candidate_mask(cand, mask_and(lt, checkerMask[1]));\n            }\n        }\n\n        return cand;\n    }\n\n    bool do_adaptive_query_round(int maxQueries, bool canAnswerAfter) {\n        bool answered = false;\n\n        for (int rep = 0; rep < maxQueries; rep++) {\n            if (Qcur >= MAXQ || elapsed() > 2.55) break;\n            if (!can_spend_ops(1)) break;\n\n            auto us = summarize_unions();\n            WeightedStates ws = collect_weighted_states();\n            if (ws.idx.empty()) break;\n\n            vector<Mask> cand = generate_candidate_masks(us, ws);\n            if (cand.empty()) break;\n\n            double bestScore = -1e100;\n            int bestId = -1;\n            for (int i = 0; i < (int)cand.size(); i++) {\n                double sc = evaluate_candidate_query(cand[i], ws);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestId = i;\n                }\n            }\n\n            double threshold = 0.25;\n            if (rep == 0 && adaptiveQueriesUsed == 0) threshold = 0.35;\n            if (bestId == -1 || bestScore < threshold) break;\n\n            if (!add_adaptive_query(cand[bestId])) break;\n            optimize_pool(5, 10, 4, false);\n\n            if (canAnswerAfter) {\n                if (try_answer_strong(0.992, false)) return true;\n                if (try_small_ambiguous_finish(12)) return true;\n            }\n        }\n\n        return answered;\n    }\n\n    // ---------- main ----------\n    void solve() {\n        stTime = chrono::steady_clock::now();\n\n        read_input();\n        build_queries();\n        precompute_placements();\n\n        bool hard = (M >= 9 || compLog2 > 78.0 || eps >= 0.14);\n\n        // Stage 1: rows + cols\n        activate_queries(0, 2 * N);\n        optimize_pool(14, 0, 6, true);\n\n        if (try_answer_strong(0.999, false)) return;\n        if (try_small_ambiguous_finish(10)) return;\n        if (do_adaptive_query_round(hard ? 4 : 3, true)) return;\n\n        auto us = summarize_unions();\n\n        bool skipMod3 = false;\n        if (hard && us.distinctUnionCount >= 10 && us.bestWeight < 0.18 && us.maxCellScore > 0.16) {\n            skipMod3 = true;\n        }\n\n        // Stage 2: mod2\n        activate_queries(2 * N, 2 * N + 4);\n        optimize_pool(8, 8, 5, false);\n\n        if (try_answer_strong(0.997, false)) return;\n        if (try_small_ambiguous_finish(12)) return;\n        if (do_adaptive_query_round(hard ? 4 : 3, true)) return;\n\n        us = summarize_unions();\n        if (hard && us.distinctUnionCount >= 8 && us.bestWeight < 0.22 && us.maxCellScore > 0.15) {\n            skipMod3 = true;\n        }\n\n        // Stage 3: mod3 if promising\n        bool promisingForMod3 = true;\n        if (hard && us.distinctUnionCount >= 8 && us.bestWeight < 0.28) promisingForMod3 = false;\n        if (adaptiveQueriesUsed >= 4 && us.bestWeight < 0.25) promisingForMod3 = false;\n\n        if (!skipMod3 && promisingForMod3) {\n            activate_queries(2 * N + 4, 2 * N + 13);\n            optimize_pool(8, 10, 5, false);\n\n            if (try_answer_strong(0.992, false)) return;\n            if (try_small_ambiguous_finish(16)) return;\n            if (do_adaptive_query_round(3, true)) return;\n        }\n\n        int heuristicLimit;\n        if (hard) heuristicLimit = 7;\n        else if (M <= 4) heuristicLimit = 18;\n        else if (M <= 8) heuristicLimit = 12;\n        else heuristicLimit = 9;\n\n        for (int step = 0; step < heuristicLimit; step++) {\n            if (elapsed() > 2.62) break;\n\n            auto cur = summarize_unions();\n\n            double wth = 0.97;\n            if ((int)drilledCells.size() >= 2) wth = 0.95;\n            if ((int)drilledCells.size() >= 4) wth = 0.92;\n\n            if (try_answer_strong(wth, true)) return;\n\n            int ambLimit = min(26, 8 + 2 * step);\n            if (try_small_ambiguous_finish(ambLimit)) return;\n\n            if (adaptiveQueriesUsed < 10 && elapsed() < 2.45) {\n                if (do_adaptive_query_round(1 + (step < 2), true)) return;\n                cur = summarize_unions();\n            }\n\n            int idx = cur.bestCell;\n            if (idx < 0) break;\n            if (ops + 2 > maxOps) break;\n\n            int val = ask_drill(idx);\n            record_drill(idx, val);\n\n            if (elapsed() < 2.5) {\n                optimize_pool(5, 10, 4, false);\n                if (!pool.empty() && pool[0].pen > 0 && elapsed() < 2.25) {\n                    optimize_pool(6, 12, 5, false);\n                }\n            }\n        }\n\n        // Last cheap attempts\n        if (try_small_ambiguous_finish(24)) return;\n        if (try_answer_strong(0.90, true)) return;\n        if (speculative_guess()) return;\n\n        full_drill_and_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long INF64 = (1LL << 60);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct Solution {\n    long long cost = INF64;\n    vector<vector<Rect>> rects; // [D][N]\n};\n\nstruct CutList {\n    int len = 0;\n    int v[50];\n};\n\nstruct DayRowLayout {\n    int l = 0, r = 0; // [l, r)\n    bool rev = false;\n    CutList cuts;\n};\n\nint D, N;\nvector<vector<int>> a; // [D][N]\n\n// prefW[(h,d,k)] = sum_{t<k} ceil(a[d][t] / h)\nvector<int> prefW;\nint strideK, strideD;\n\ninline int pref_idx(int h, int d, int k) {\n    return h * strideD + d * strideK + k;\n}\ninline int sum_widths(int h, int d, int l, int r) {\n    return prefW[pref_idx(h, d, r)] - prefW[pref_idx(h, d, l)];\n}\ninline int cell_width(int h, int d, int k) {\n    return prefW[pref_idx(h, d, k + 1)] - prefW[pref_idx(h, d, k)];\n}\n\ninline int count_common_arr(const int* A, int nA, const int* B, int nB) {\n    int i = 0, j = 0, c = 0;\n    while (i < nA && j < nB) {\n        if (A[i] == B[j]) {\n            ++c; ++i; ++j;\n        } else if (A[i] < B[j]) {\n            ++i;\n        } else {\n            ++j;\n        }\n    }\n    return c;\n}\n\ninline int count_common_cut(const CutList& A, const CutList& B) {\n    return count_common_arr(A.v, A.len, B.v, B.len);\n}\n\ninline long long dist_cut(const CutList& A, const CutList& B, int h) {\n    int common = count_common_cut(A, B);\n    return 1LL * h * (A.len + B.len - 2 * common);\n}\n\ninline long long dist_cut_arr(const CutList& A, const int* B, int lenB, int h) {\n    int common = count_common_arr(A.v, A.len, B, lenB);\n    return 1LL * h * (A.len + lenB - 2 * common);\n}\n\ninline void build_cuts(int h, int d, int l, int r, bool rev, CutList& out) {\n    out.len = max(0, r - l - 1);\n    int s = 0, p = 0;\n    if (!rev) {\n        for (int k = l; k < r - 1; ++k) {\n            s += cell_width(h, d, k);\n            out.v[p++] = s;\n        }\n    } else {\n        for (int k = r - 1; k > l; --k) {\n            s += cell_width(h, d, k);\n            out.v[p++] = s;\n        }\n    }\n}\n\n// ---------- Exact evaluator ----------\n\nlong long evaluate_exact(const vector<vector<Rect>>& rects) {\n    const int HS = (W - 1) * W;     // horizontal interior segments\n    const int VS = W * (W - 1);     // vertical interior segments\n    const int HWORDS = (HS + 63) >> 6;\n    const int VWORDS = (VS + 63) >> 6;\n\n    vector<uint64_t> prevH(HWORDS, 0), prevV(VWORDS, 0);\n    vector<uint64_t> curH(HWORDS, 0), curV(VWORDS, 0);\n\n    auto setbit = [](vector<uint64_t>& bits, int idx) {\n        bits[idx >> 6] |= (1ULL << (idx & 63));\n    };\n\n    long long cost = 0;\n\n    for (int d = 0; d < D; ++d) {\n        fill(curH.begin(), curH.end(), 0);\n        fill(curV.begin(), curV.end(), 0);\n\n        for (int k = 0; k < N; ++k) {\n            const auto& r = rects[d][k];\n\n            long long area = 1LL * (r.i1 - r.i0) * (r.j1 - r.j0);\n            if (area < a[d][k]) cost += 100LL * (a[d][k] - area);\n\n            if (r.i0 > 0) {\n                int base = (r.i0 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.i1 < W) {\n                int base = (r.i1 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.j0 > 0) {\n                int x = r.j0 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n            if (r.j1 < W) {\n                int x = r.j1 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n        }\n\n        if (d > 0) {\n            for (int i = 0; i < HWORDS; ++i) cost += __builtin_popcountll(prevH[i] ^ curH[i]);\n            for (int i = 0; i < VWORDS; ++i) cost += __builtin_popcountll(prevV[i] ^ curV[i]);\n        }\n\n        prevH.swap(curH);\n        prevV.swap(curV);\n    }\n\n    return cost;\n}\n\n// ---------- Candidate 1: fixed full-width strips ----------\n\nlong long marginal_gain_all_days(int idx, int cur_h) {\n    long long gain = 0;\n    int area = W * cur_h;\n    for (int d = 0; d < D; ++d) {\n        int rem = a[d][idx] - area;\n        if (rem > 0) gain += 100LL * min(W, rem);\n    }\n    return gain;\n}\n\nvector<int> optimize_fixed_strips_all_days() {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>; // gain, idx, current_h\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_all_days(i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            rem = 0;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_all_days(idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_fixed_strips() {\n    Solution sol;\n    vector<int> h = optimize_fixed_strips_all_days();\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Candidate 2: day-by-day strips ----------\n\nlong long marginal_gain_one_day(int d, int idx, int cur_h) {\n    int area = W * cur_h;\n    int rem = a[d][idx] - area;\n    if (rem <= 0) return 0;\n    return 100LL * min(W, rem);\n}\n\nvector<int> optimize_strips_one_day(int d) {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>;\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_one_day(d, i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            rem = 0;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_one_day(d, idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_daily_strips() {\n    Solution sol;\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        vector<int> h = optimize_strips_one_day(d);\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Candidate 3: old row-DP with fixed intervals across all days ----------\n\nstruct RowChoice {\n    int l, r;\n    int h;\n    int last_idx;\n    bool rev;\n};\n\nstruct RowDPResult {\n    Solution sol;\n    vector<int> heights;\n    bool feasible = false;\n};\n\nRowDPResult solve_row_dp_zero_shortage_fixed_intervals() {\n    RowDPResult res;\n    res.sol.cost = INF64;\n\n    auto interval_ok = [&](int l, int r, int h) -> bool {\n        for (int d = 0; d < D; ++d) {\n            if (sum_widths(h, d, l, r) > W) return false;\n        }\n        return true;\n    };\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    vector<vector<long long>> rowCost(N + 1, vector<long long>(N + 1, INF64));\n    vector<vector<int>> bestLast(N + 1, vector<int>(N + 1, -1));\n    vector<vector<char>> bestRev(N + 1, vector<char>(N + 1, 0));\n\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            if (!interval_ok(l, r, W)) continue;\n\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (interval_ok(l, r, mid)) hi = mid;\n                else lo = mid + 1;\n            }\n            int h = lo;\n            reqH[l][r] = h;\n\n            int m = r - l;\n            if (m == 1) {\n                rowCost[l][r] = 0;\n                bestLast[l][r] = l;\n                bestRev[l][r] = 0;\n                continue;\n            }\n\n            long long bestC = INF64;\n            int bestP = l;\n            bool bestR = false;\n\n            int prevCuts[55], curCuts[55];\n            for (int p = l; p < r; ++p) {\n                for (int rev = 0; rev <= 1; ++rev) {\n                    long long total = 0;\n                    int prevLen = 0;\n\n                    for (int d = 0; d < D; ++d) {\n                        int len = 0, s = 0;\n                        if (!rev) {\n                            for (int k = l; k < r; ++k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        } else {\n                            for (int k = r - 1; k >= l; --k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        }\n\n                        if (d > 0) {\n                            int common = count_common_arr(prevCuts, prevLen, curCuts, len);\n                            total += 2LL * h * (len - common);\n                        }\n                        prevLen = len;\n                        for (int i = 0; i < len; ++i) prevCuts[i] = curCuts[i];\n                    }\n\n                    if (total < bestC) {\n                        bestC = total;\n                        bestP = p;\n                        bestR = (bool)rev;\n                    }\n                }\n            }\n\n            rowCost[l][r] = bestC;\n            bestLast[l][r] = bestP;\n            bestRev[l][r] = (char)bestR;\n        }\n    }\n\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, INF64));\n    vector<vector<short>> prvI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> prvH(N + 1, vector<short>(W + 1, -1));\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] >= INF64) continue;\n            for (int j = i + 1; j <= N; ++j) {\n                int h = reqH[i][j];\n                if (h > W || used + h > W) continue;\n                long long nd = dp[i][used] + rowCost[i][j];\n                if (nd < dp[j][used + h]) {\n                    dp[j][used + h] = nd;\n                    prvI[j][used + h] = (short)i;\n                    prvH[j][used + h] = (short)used;\n                }\n            }\n        }\n    }\n\n    int bestUsed = -1;\n    long long bestVal = INF64;\n    for (int used = 0; used <= W; ++used) {\n        if (dp[N][used] < bestVal) {\n            bestVal = dp[N][used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0 || bestVal >= INF64) return res;\n\n    vector<RowChoice> rows;\n    {\n        int ci = N, ch = bestUsed;\n        while (ci > 0) {\n            int pi = prvI[ci][ch];\n            int ph = prvH[ci][ch];\n            RowChoice rc;\n            rc.l = pi;\n            rc.r = ci;\n            rc.h = reqH[pi][ci];\n            rc.last_idx = bestLast[pi][ci];\n            rc.rev = bestRev[pi][ci];\n            rows.push_back(rc);\n            ci = pi;\n            ch = ph;\n        }\n        reverse(rows.begin(), rows.end());\n    }\n\n    res.heights.clear();\n    for (auto& rc : rows) res.heights.push_back(rc.h);\n\n    res.sol.rects.assign(D, vector<Rect>(N));\n    int y = 0;\n    for (const auto& row : rows) {\n        int l = row.l, r = row.r, h = row.h, p = row.last_idx;\n        bool rev = row.rev;\n\n        for (int d = 0; d < D; ++d) {\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r; ++k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            } else {\n                for (int k = r - 1; k >= l; --k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            }\n            res.sol.rects[d][p] = {y, x, y + h, W};\n        }\n        y += h;\n    }\n\n    res.sol.cost = evaluate_exact(res.sol.rects);\n    res.feasible = true;\n    return res;\n}\n\n// ---------- New candidate: fixed row heights, variable intervals per day + local improvement ----------\n\nbool optimize_one_day_for_pattern(\n    int d,\n    const vector<int>& hs,\n    const vector<DayRowLayout>* prevDay,\n    const vector<DayRowLayout>* nextDay,\n    bool useProxy,\n    vector<DayRowLayout>& out\n) {\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return false;\n\n    static long long intervalCost[55][55][55];\n    static unsigned char intervalRev[55][55][55];\n    static long long dp[55][55];\n    static short parL[55][55];\n    static unsigned char parRev[55][55];\n\n    for (int row = 0; row < R; ++row) {\n        int h = hs[row];\n        const CutList* pc = prevDay ? &((*prevDay)[row].cuts) : nullptr;\n        const CutList* nc = nextDay ? &((*nextDay)[row].cuts) : nullptr;\n\n        for (int l = 0; l <= N; ++l) {\n            for (int r = 0; r <= N; ++r) {\n                intervalCost[row][l][r] = INF64;\n                intervalRev[row][l][r] = 0;\n            }\n        }\n\n        for (int l = 0; l < N; ++l) {\n            for (int r = l + 1; r <= N; ++r) {\n                if (sum_widths(h, d, l, r) > W) continue;\n\n                int fcuts[50], rcuts[50];\n                int flen = r - l - 1;\n                int rlen = r - l - 1;\n\n                {\n                    int s = 0, p = 0;\n                    for (int k = l; k < r - 1; ++k) {\n                        s += cell_width(h, d, k);\n                        fcuts[p++] = s;\n                    }\n                }\n                {\n                    int s = 0, p = 0;\n                    for (int k = r - 1; k > l; --k) {\n                        s += cell_width(h, d, k);\n                        rcuts[p++] = s;\n                    }\n                }\n\n                auto calc_cost = [&](const int* cuts, int len) -> long long {\n                    long long c = 0;\n                    if (pc) c += dist_cut_arr(*pc, cuts, len, h);\n                    if (nc) c += dist_cut_arr(*nc, cuts, len, h);\n                    if (!pc && !nc && useProxy) c += 1LL * h * len;\n                    return c;\n                };\n\n                long long c0 = calc_cost(fcuts, flen);\n                long long c1 = calc_cost(rcuts, rlen);\n\n                if (c1 < c0) {\n                    intervalCost[row][l][r] = c1;\n                    intervalRev[row][l][r] = 1;\n                } else {\n                    intervalCost[row][l][r] = c0;\n                    intervalRev[row][l][r] = 0;\n                }\n            }\n        }\n    }\n\n    for (int i = 0; i <= R; ++i) {\n        for (int j = 0; j <= N; ++j) {\n            dp[i][j] = INF64;\n            parL[i][j] = -1;\n            parRev[i][j] = 0;\n        }\n    }\n    dp[0][0] = 0;\n\n    for (int row = 0; row < R; ++row) {\n        for (int l = 0; l <= N; ++l) {\n            if (dp[row][l] >= INF64) continue;\n            int minR = l + 1;\n            int maxR = N - (R - row - 1);\n            for (int r = minR; r <= maxR; ++r) {\n                long long c = intervalCost[row][l][r];\n                if (c >= INF64) continue;\n                long long nd = dp[row][l] + c;\n                if (nd < dp[row + 1][r]) {\n                    dp[row + 1][r] = nd;\n                    parL[row + 1][r] = (short)l;\n                    parRev[row + 1][r] = intervalRev[row][l][r];\n                }\n            }\n        }\n    }\n\n    if (dp[R][N] >= INF64) return false;\n\n    out.assign(R, DayRowLayout{});\n    int cur = N;\n    for (int row = R; row >= 1; --row) {\n        int l = parL[row][cur];\n        bool rev = parRev[row][cur];\n        out[row - 1].l = l;\n        out[row - 1].r = cur;\n        out[row - 1].rev = rev;\n        build_cuts(hs[row - 1], d, l, cur, rev, out[row - 1].cuts);\n        cur = l;\n    }\n    return true;\n}\n\nSolution solve_fixed_height_pattern(const vector<int>& hs) {\n    Solution sol;\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return sol;\n    int sumH = 0;\n    for (int h : hs) {\n        if (h <= 0) return sol;\n        sumH += h;\n    }\n    if (sumH > W) return sol;\n\n    vector<vector<DayRowLayout>> lay(D, vector<DayRowLayout>(R));\n\n    // initial independent layouts\n    for (int d = 0; d < D; ++d) {\n        if (!optimize_one_day_for_pattern(d, hs, nullptr, nullptr, true, lay[d])) {\n            return sol;\n        }\n    }\n\n    // local improvement: coordinate descent on days\n    for (int iter = 0; iter < 2; ++iter) {\n        for (int d = 0; d < D; ++d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, lay[d])) {\n                return sol;\n            }\n        }\n        for (int d = D - 1; d >= 0; --d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, lay[d])) {\n                return sol;\n            }\n        }\n    }\n\n    sol.rects.assign(D, vector<Rect>(N));\n    vector<int> y0(R + 1, 0);\n    for (int r = 0; r < R; ++r) y0[r + 1] = y0[r] + hs[r];\n\n    for (int d = 0; d < D; ++d) {\n        for (int row = 0; row < R; ++row) {\n            int y = y0[row];\n            int h = hs[row];\n            int l = lay[d][row].l;\n            int r = lay[d][row].r;\n            bool rev = lay[d][row].rev;\n\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r - 1; ++k) {\n                    int w = cell_width(h, d, k);\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n                sol.rects[d][r - 1] = {y, x, y + h, W};\n            } else {\n                for (int k = r - 1; k > l; --k) {\n                    int w = cell_width(h, d, k);\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n                sol.rects[d][l] = {y, x, y + h, W};\n            }\n        }\n    }\n\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Single-day min-height pattern (for one representative day) ----------\n\nvector<int> compute_day_minheight_pattern(int dsel) {\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            if (sum_widths(W, dsel, l, r) > W) continue;\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (sum_widths(mid, dsel, l, r) <= W) hi = mid;\n                else lo = mid + 1;\n            }\n            reqH[l][r] = lo;\n        }\n    }\n\n    vector<int> dpH(N + 1, W + 1), dpRows(N + 1, 1e9), parent(N + 1, -1);\n    dpH[0] = 0;\n    dpRows[0] = 0;\n\n    for (int r = 1; r <= N; ++r) {\n        for (int l = 0; l < r; ++l) {\n            if (reqH[l][r] > W || dpH[l] > W) continue;\n            int nh = dpH[l] + reqH[l][r];\n            int nr = dpRows[l] + 1;\n            if (nh < dpH[r] || (nh == dpH[r] && nr < dpRows[r])) {\n                dpH[r] = nh;\n                dpRows[r] = nr;\n                parent[r] = l;\n            }\n        }\n    }\n\n    if (dpH[N] > W) return {};\n\n    vector<int> hs;\n    int cur = N;\n    while (cur > 0) {\n        int l = parent[cur];\n        hs.push_back(reqH[l][cur]);\n        cur = l;\n    }\n    reverse(hs.begin(), hs.end());\n    sort(hs.begin(), hs.end());\n    return hs;\n}\n\n// ---------- Helpers ----------\n\nvector<int> make_equal_heights(int R) {\n    if (R <= 0) return {};\n    vector<int> hs(R, W / R);\n    int rem = W % R;\n    for (int i = 0; i < rem; ++i) hs[R - 1 - i]++;\n    return hs;\n}\n\nvoid consider_best(Solution& best, Solution cand) {\n    if (cand.cost < best.cost) best = std::move(cand);\n}\n\n// ---------- Main ----------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\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    // Precompute prefW\n    strideK = N + 1;\n    strideD = D * strideK;\n    prefW.assign((W + 1) * strideD, 0);\n\n    for (int h = 1; h <= W; ++h) {\n        for (int d = 0; d < D; ++d) {\n            prefW[pref_idx(h, d, 0)] = 0;\n            for (int k = 0; k < N; ++k) {\n                prefW[pref_idx(h, d, k + 1)] = prefW[pref_idx(h, d, k)] + (a[d][k] + h - 1) / h;\n            }\n        }\n    }\n\n    Solution best;\n    best.cost = INF64;\n\n    // Keep simple fallbacks\n    consider_best(best, solve_fixed_strips());\n    consider_best(best, solve_daily_strips());\n\n    // Old fixed-interval row DP\n    RowDPResult rowdp = solve_row_dp_zero_shortage_fixed_intervals();\n    if (rowdp.feasible) consider_best(best, rowdp.sol);\n\n    // Height-pattern candidates for the new solver\n    vector<vector<int>> patterns;\n    auto add_pattern = [&](vector<int> hs) {\n        if (hs.empty()) return;\n        int sumH = 0;\n        for (int h : hs) sumH += h;\n        if (sumH > W) return;\n        if ((int)hs.size() > N) return;\n        patterns.push_back(std::move(hs));\n    };\n\n    // Equal-height shelves\n    for (int R = 1; R <= min(N, 10); ++R) add_pattern(make_equal_heights(R));\n\n    // Heights from old row-DP\n    if (rowdp.feasible) {\n        add_pattern(rowdp.heights);\n        vector<int> hs2 = rowdp.heights;\n        sort(hs2.begin(), hs2.end());\n        add_pattern(hs2);\n    }\n\n    // One representative daily pattern: max total area day\n    int bestDay = 0;\n    long long bestSum = -1;\n    for (int d = 0; d < D; ++d) {\n        long long s = 0;\n        for (int k = 0; k < N; ++k) s += a[d][k];\n        if (s > bestSum) {\n            bestSum = s;\n            bestDay = d;\n        }\n    }\n    add_pattern(compute_day_minheight_pattern(bestDay));\n\n    // Deduplicate exact vectors\n    sort(patterns.begin(), patterns.end());\n    patterns.erase(unique(patterns.begin(), patterns.end()), patterns.end());\n\n    // New strong candidates\n    for (const auto& hs : patterns) {\n        Solution cand = solve_fixed_height_pattern(hs);\n        consider_best(best, std::move(cand));\n    }\n\n    // Output\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            const auto& r = best.rects[d][k];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nusing i64 = long long;\nusing u32 = uint32_t;\n\nstatic constexpr u32 MOD = 998244353;\nstatic constexpr int N = 9;\nstatic constexpr int M = 20;\nstatic constexpr int K = 81;\n\n// Up to how many stamps to consider as one \"combo\" on a position.\nstatic constexpr int BEAM_COMBO_MAX = 3;\nstatic constexpr int REFINE_COMBO_MAX = 5;\n\n// Beam parameters\nstatic constexpr int BEAM_WIDTH_PER_USED = 3;\nstatic constexpr int TOP_SINGLE = 2;\nstatic constexpr int TOP_PAIR = 2;\nstatic constexpr int TOP_TRIPLE = 1;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 0) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nstruct Combo {\n    uint8_t cost = 0;\n    uint8_t ids[REFINE_COMBO_MAX]{}; // nondecreasing stamp ids\n    u32 add[9]{};                    // net 3x3 addition modulo MOD\n};\n\nstruct BeamNode {\n    u32 board[81]{};\n    i64 score = 0;\n    uint8_t used = 0;\n    int parent = -1;   // index in previous layer\n    int combo_id = -1; // combo chosen at this step\n};\n\nstruct Solution {\n    u32 board[81]{};\n    i64 score = 0;\n    int used = 0;\n    u32 pos_add[49][9]{};                       // net addition at each position\n    uint8_t pos_count[49]{};                    // number of stamps at each position\n    uint8_t pos_ids[49][REFINE_COMBO_MAX]{};    // actual stamps used\n};\n\nclass Solver {\npublic:\n    Timer timer;\n    SplitMix64 rng;\n\n    u32 init_board[81]{};\n    i64 init_score = 0;\n    u32 stamp[20][9]{};\n    uint8_t pos_cells[49][9]{};\n\n    vector<Combo> combos;\n    array<vector<int>, REFINE_COMBO_MAX + 1> combo_ids_by_cost;\n\n    void read_input() {\n        int n, m, k;\n        cin >> n >> m >> k;\n        (void)n; (void)m; (void)k;\n\n        uint64_t seed = 0x123456789abcdef0ULL;\n        auto mix = [&](uint64_t v) {\n            seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        };\n\n        for (int i = 0; i < 81; i++) {\n            cin >> init_board[i];\n            init_score += init_board[i];\n            mix(init_board[i] + 1000003ULL * (i + 1));\n        }\n        for (int m0 = 0; m0 < 20; m0++) {\n            for (int i = 0; i < 3; i++) {\n                for (int j = 0; j < 3; j++) {\n                    cin >> stamp[m0][i * 3 + j];\n                    mix(stamp[m0][i * 3 + j] + 10007ULL * (m0 + 1) + 131ULL * i + j);\n                }\n            }\n        }\n        rng = SplitMix64(seed);\n\n        build_pos_cells();\n        build_combos();\n    }\n\n    void solve() {\n        const double TL_MAIN = 1.95;\n\n        Solution best = build_by_beam();\n        refine_coordinate_ascent(best, min(TL_MAIN, 1.55), 4);\n\n        while (timer.elapsed() < TL_MAIN - 0.02) {\n            Solution cur = best;\n            random_destroy(cur);\n\n            double sub_limit = min(TL_MAIN - 0.01, timer.elapsed() + 0.10);\n            refine_coordinate_ascent(cur, sub_limit, 2);\n\n            if (better(cur, best)) best = std::move(cur);\n        }\n\n        refine_coordinate_ascent(best, TL_MAIN, 3);\n        output(best);\n    }\n\nprivate:\n    void build_pos_cells() {\n        for (int p = 0; p < 7; p++) {\n            for (int q = 0; q < 7; q++) {\n                int pos = p * 7 + q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        pos_cells[pos][t++] = (uint8_t)((p + i) * 9 + (q + j));\n                    }\n                }\n            }\n        }\n    }\n\n    static inline i64 add_gain_cell(u32 x, u32 s) {\n        return (x + s >= MOD) ? (i64)s - MOD : (i64)s;\n    }\n\n    static inline i64 remove_gain_cell(u32 x, u32 s) {\n        return (x >= s) ? -(i64)s : (i64)MOD - s;\n    }\n\n    inline i64 gain_local(const u32 x[9], const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += add_gain_cell(x[k], add[k]);\n        return g;\n    }\n\n    inline void extract_local(const u32 board[81], int pos, u32 x[9]) const {\n        for (int k = 0; k < 9; k++) x[k] = board[pos_cells[pos][k]];\n    }\n\n    inline i64 gain_add_pos(const u32 board[81], int pos, const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += add_gain_cell(board[pos_cells[pos][k]], add[k]);\n        return g;\n    }\n\n    inline i64 gain_remove_pos(const u32 board[81], int pos, const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += remove_gain_cell(board[pos_cells[pos][k]], add[k]);\n        return g;\n    }\n\n    inline void apply_add_pos(u32 board[81], int pos, const u32 add[9]) const {\n        for (int k = 0; k < 9; k++) {\n            u32 &v = board[pos_cells[pos][k]];\n            v += add[k];\n            if (v >= MOD) v -= MOD;\n        }\n    }\n\n    inline void apply_remove_pos(u32 board[81], int pos, const u32 add[9]) const {\n        for (int k = 0; k < 9; k++) {\n            u32 &v = board[pos_cells[pos][k]];\n            u32 s = add[k];\n            if (v >= s) v -= s;\n            else v = v + MOD - s;\n        }\n    }\n\n    void build_combos() {\n        combos.clear();\n        for (auto &v : combo_ids_by_cost) v.clear();\n        combos.reserve(60000);\n\n        Combo zero;\n        zero.cost = 0;\n        int id0 = (int)combos.size();\n        combos.push_back(zero);\n        combo_ids_by_cost[0].push_back(id0);\n\n        u32 cur[9]{};\n        uint8_t ids[REFINE_COMBO_MAX]{};\n\n        function<void(int,int,int)> dfs = [&](int start, int depth, int target) {\n            if (depth == target) {\n                Combo c;\n                c.cost = (uint8_t)target;\n                for (int i = 0; i < target; i++) c.ids[i] = ids[i];\n                for (int k = 0; k < 9; k++) c.add[k] = cur[k];\n                int idx = (int)combos.size();\n                combos.push_back(c);\n                combo_ids_by_cost[target].push_back(idx);\n                return;\n            }\n            for (int m0 = start; m0 < 20; m0++) {\n                ids[depth] = (uint8_t)m0;\n                for (int k = 0; k < 9; k++) {\n                    u32 x = cur[k] + stamp[m0][k];\n                    if (x >= MOD) x -= MOD;\n                    cur[k] = x;\n                }\n                dfs(m0, depth + 1, target);\n                for (int k = 0; k < 9; k++) {\n                    u32 s = stamp[m0][k];\n                    if (cur[k] >= s) cur[k] -= s;\n                    else cur[k] = cur[k] + MOD - s;\n                }\n            }\n        };\n\n        for (int cost = 1; cost <= REFINE_COMBO_MAX; cost++) {\n            dfs(0, 0, cost);\n        }\n    }\n\n    template<size_t SZ>\n    static inline void push_top(array<pair<i64,int>, SZ>& best, i64 gain, int cid) {\n        for (size_t i = 0; i < SZ; i++) {\n            if (gain > best[i].first) {\n                for (size_t j = SZ - 1; j > i; j--) best[j] = best[j - 1];\n                best[i] = {gain, cid};\n                return;\n            }\n        }\n    }\n\n    Solution build_by_beam() {\n        vector<vector<BeamNode>> layers(50);\n\n        BeamNode root;\n        memcpy(root.board, init_board, sizeof(init_board));\n        root.score = init_score;\n        root.used = 0;\n        root.parent = -1;\n        root.combo_id = -1;\n        layers[0].push_back(root);\n\n        array<vector<int>, K + 1> bucket_idx_cur, bucket_idx_nxt;\n        bucket_idx_cur[0].push_back(0);\n\n        for (int step = 0; step < 49; step++) {\n            array<vector<BeamNode>, K + 1> cand;\n            const auto &cur_layer = layers[step];\n\n            for (int used = 0; used <= K; used++) {\n                for (int idx : bucket_idx_cur[used]) {\n                    const BeamNode &st = cur_layer[idx];\n                    int pos = step;\n\n                    u32 x[9];\n                    extract_local(st.board, pos, x);\n\n                    array<pair<i64,int>, TOP_SINGLE> best1;\n                    array<pair<i64,int>, TOP_PAIR> best2;\n                    array<pair<i64,int>, TOP_TRIPLE> best3;\n                    for (auto &p : best1) p = {-(1LL << 60), -1};\n                    for (auto &p : best2) p = {-(1LL << 60), -1};\n                    for (auto &p : best3) p = {-(1LL << 60), -1};\n\n                    if (used + 1 <= K) {\n                        for (int cid : combo_ids_by_cost[1]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best1, g, cid);\n                        }\n                    }\n                    if (used + 2 <= K) {\n                        for (int cid : combo_ids_by_cost[2]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best2, g, cid);\n                        }\n                    }\n                    if (used + 3 <= K) {\n                        for (int cid : combo_ids_by_cost[3]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best3, g, cid);\n                        }\n                    }\n\n                    auto make_child = [&](int cid) {\n                        const Combo &cb = combos[cid];\n                        BeamNode ch;\n                        memcpy(ch.board, st.board, sizeof(st.board));\n                        apply_add_pos(ch.board, pos, cb.add);\n                        ch.score = st.score + gain_local(x, cb.add);\n                        ch.used = (uint8_t)(used + cb.cost);\n                        ch.parent = idx;\n                        ch.combo_id = cid;\n                        cand[ch.used].push_back(std::move(ch));\n                    };\n\n                    make_child(combo_ids_by_cost[0][0]); // no-op\n                    for (auto [g, cid] : best1) if (cid != -1) make_child(cid);\n                    for (auto [g, cid] : best2) if (cid != -1) make_child(cid);\n                    for (auto [g, cid] : best3) if (cid != -1) make_child(cid);\n                }\n            }\n\n            vector<BeamNode> next_layer;\n            for (auto &v : bucket_idx_nxt) v.clear();\n\n            for (int used = 0; used <= K; used++) {\n                auto &vec = cand[used];\n                if (vec.empty()) continue;\n                sort(vec.begin(), vec.end(), [](const BeamNode &a, const BeamNode &b) {\n                    return a.score > b.score;\n                });\n                if ((int)vec.size() > BEAM_WIDTH_PER_USED) vec.resize(BEAM_WIDTH_PER_USED);\n                for (auto &node : vec) {\n                    bucket_idx_nxt[used].push_back((int)next_layer.size());\n                    next_layer.push_back(std::move(node));\n                }\n            }\n\n            layers[step + 1] = std::move(next_layer);\n            bucket_idx_cur = std::move(bucket_idx_nxt);\n        }\n\n        int best_idx = 0;\n        i64 best_score = -(1LL << 60);\n        for (int i = 0; i < (int)layers[49].size(); i++) {\n            if (layers[49][i].score > best_score) {\n                best_score = layers[49][i].score;\n                best_idx = i;\n            }\n        }\n\n        int chosen_combo[49];\n        int cur = best_idx;\n        for (int step = 49; step >= 1; step--) {\n            chosen_combo[step - 1] = layers[step][cur].combo_id;\n            cur = layers[step][cur].parent;\n        }\n\n        Solution sol;\n        memcpy(sol.board, layers[49][best_idx].board, sizeof(sol.board));\n        sol.score = layers[49][best_idx].score;\n        sol.used = 0;\n\n        for (int pos = 0; pos < 49; pos++) {\n            const Combo &cb = combos[chosen_combo[pos]];\n            sol.pos_count[pos] = cb.cost;\n            for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = cb.add[k];\n            for (int t = 0; t < REFINE_COMBO_MAX; t++) {\n                sol.pos_ids[pos][t] = (t < cb.cost ? cb.ids[t] : 0);\n            }\n            sol.used += cb.cost;\n        }\n\n        return sol;\n    }\n\n    static bool same_add_and_count(const u32 a[9], int ca, const u32 b[9], int cb) {\n        if (ca != cb) return false;\n        for (int k = 0; k < 9; k++) if (a[k] != b[k]) return false;\n        return true;\n    }\n\n    void shuffle_positions(int ord[49]) {\n        for (int i = 48; i > 0; i--) {\n            int j = rng.next_int(i + 1);\n            swap(ord[i], ord[j]);\n        }\n    }\n\n    void refine_coordinate_ascent(Solution &sol, double time_limit, int max_rounds) {\n        int ord[49];\n        iota(ord, ord + 49, 0);\n\n        int rounds = 0;\n        while (timer.elapsed() < time_limit && rounds < max_rounds) {\n            rounds++;\n            shuffle_positions(ord);\n            bool changed = false;\n\n            for (int it = 0; it < 49; it++) {\n                if (timer.elapsed() >= time_limit) return;\n\n                int pos = ord[it];\n\n                u32 old_add[9];\n                for (int k = 0; k < 9; k++) old_add[k] = sol.pos_add[pos][k];\n                int old_count = sol.pos_count[pos];\n                uint8_t old_ids[REFINE_COMBO_MAX];\n                for (int t = 0; t < REFINE_COMBO_MAX; t++) old_ids[t] = sol.pos_ids[pos][t];\n\n                if (old_count > 0) {\n                    sol.score += gain_remove_pos(sol.board, pos, old_add);\n                    apply_remove_pos(sol.board, pos, old_add);\n                }\n\n                u32 x[9];\n                extract_local(sol.board, pos, x);\n\n                i64 old_delta = gain_local(x, old_add);\n                int other_used = sol.used - old_count;\n                int available = K - other_used;\n                int maxc = min(REFINE_COMBO_MAX, available);\n\n                i64 best_delta = old_delta;\n                int best_cost = old_count;\n                int best_cid = -1;\n\n                for (int c = 0; c <= maxc; c++) {\n                    for (int cid : combo_ids_by_cost[c]) {\n                        i64 d = gain_local(x, combos[cid].add);\n                        if (d > best_delta || (d == best_delta && c < best_cost)) {\n                            best_delta = d;\n                            best_cost = c;\n                            best_cid = cid;\n                        }\n                    }\n                }\n\n                if (best_cid == -1) {\n                    if (old_count > 0) {\n                        sol.score += old_delta;\n                        apply_add_pos(sol.board, pos, old_add);\n                    }\n                    continue;\n                }\n\n                const Combo &cb = combos[best_cid];\n                sol.score += best_delta;\n                apply_add_pos(sol.board, pos, cb.add);\n\n                sol.used = other_used + cb.cost;\n                sol.pos_count[pos] = cb.cost;\n                for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = cb.add[k];\n                for (int t = 0; t < REFINE_COMBO_MAX; t++) {\n                    sol.pos_ids[pos][t] = (t < cb.cost ? cb.ids[t] : 0);\n                }\n\n                if (!same_add_and_count(old_add, old_count, cb.add, cb.cost)) changed = true;\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void remove_position_combo(Solution &sol, int pos) {\n        int cnt = sol.pos_count[pos];\n        if (cnt == 0) return;\n        sol.score += gain_remove_pos(sol.board, pos, sol.pos_add[pos]);\n        apply_remove_pos(sol.board, pos, sol.pos_add[pos]);\n        sol.used -= cnt;\n        sol.pos_count[pos] = 0;\n        for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = 0;\n        for (int t = 0; t < REFINE_COMBO_MAX; t++) sol.pos_ids[pos][t] = 0;\n    }\n\n    void random_destroy(Solution &sol) {\n        vector<int> nonzero;\n        nonzero.reserve(49);\n        for (int pos = 0; pos < 49; pos++) {\n            if (sol.pos_count[pos] > 0) nonzero.push_back(pos);\n        }\n        if (nonzero.empty()) return;\n\n        int r = 1 + rng.next_int(min(4, (int)nonzero.size()));\n        for (int i = 0; i < r; i++) {\n            int j = i + rng.next_int((int)nonzero.size() - i);\n            swap(nonzero[i], nonzero[j]);\n        }\n        for (int i = 0; i < r; i++) {\n            remove_position_combo(sol, nonzero[i]);\n        }\n    }\n\n    static bool better(const Solution &a, const Solution &b) {\n        if (a.score != b.score) return a.score > b.score;\n        return a.used < b.used;\n    }\n\n    void output(const Solution &sol) {\n        cout << sol.used << '\\n';\n        for (int pos = 0; pos < 49; pos++) {\n            int p = pos / 7;\n            int q = pos % 7;\n            for (int t = 0; t < sol.pos_count[pos]; t++) {\n                cout << (int)sol.pos_ids[pos][t] << ' ' << p << ' ' << q << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int CNUM = 25;\nstatic constexpr long long INF_SCORE = (long long)4e18;\n\nstruct Result {\n    long long score = INF_SCORE;\n    vector<string> out;\n};\n\nstruct Planner {\n    int A[N][N];\n\n    // Parameters\n    int handoff;      // 2 or 3\n    int mode;         // 0 = greedy, 1 = source-batch\n    int policy;       // tie-breaking / metric style\n    int ready_bias;   // used in batch mode\n    int slot_policy;  // 0 = balanced, 1 = source-biased\n\n    int src_of[CNUM], pos_of[CNUM];\n\n    int idx[N];                 // next unseen index in source row\n    bool done[CNUM];\n    int need[N];                // next required id for each dispatch row\n\n    // loc_type: 0 hidden/source, 1 buffered on grid, 2 dispatched\n    int loc_type[CNUM];\n    pair<int,int> buf_pos[CNUM];\n\n    // planner-side occupancy for buffered containers only\n    int buffer_occ[N][N];\n\n    int done_cnt = 0;\n\n    struct Crane {\n        bool alive = true;\n        int r = 0, c = 0;\n        int hold = -1;\n        bool large = false;\n    };\n    Crane cranes[N];\n\n    // actual simulator state\n    int cont[N][N];\n    int arrival_idx[N];\n\n    vector<string> out;\n    int T = 0;\n    bool illegal = false;\n\n    vector<int> dispatched[N];\n\n    Planner(const int inputA[N][N], int handoff_, int mode_, int policy_, int ready_bias_, int slot_policy_)\n        : handoff(handoff_), mode(mode_), policy(policy_), ready_bias(ready_bias_), slot_policy(slot_policy_) {\n        memset(src_of, -1, sizeof(src_of));\n        memset(pos_of, -1, sizeof(pos_of));\n        memset(idx, 0, sizeof(idx));\n        memset(done, 0, sizeof(done));\n        memset(loc_type, 0, sizeof(loc_type));\n        memset(buffer_occ, -1, sizeof(buffer_occ));\n        memset(cont, -1, sizeof(cont));\n        memset(arrival_idx, 0, sizeof(arrival_idx));\n        out.assign(N, \"\");\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) A[i][j] = inputA[i][j];\n    }\n\n    static int mdist(pair<int,int> a, pair<int,int> b) {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    bool assigned_row(int d) const { return d >= 1; }\n\n    pair<int,int> cur_pos() const { return {cranes[0].r, cranes[0].c}; }\n\n    bool is_move(char ch) const {\n        return ch == 'U' || ch == 'D' || ch == 'L' || ch == 'R';\n    }\n\n    void update_need(int d) {\n        while (need[d] <= d * N + (N - 1) && done[need[d]]) need[d]++;\n    }\n\n    bool row_pending_small(int d) const {\n        if (!assigned_row(d)) return false;\n        int t = need[d];\n        if (t > d * N + (N - 1)) return false;\n        if (cranes[d].hold == t) return true;\n        if (cont[d][handoff] == t) return true;\n        return false;\n    }\n\n    void mark_done(int id) {\n        if (id < 0 || id >= CNUM) return;\n        if (done[id]) return;\n        done[id] = true;\n        loc_type[id] = 2;\n        done_cnt++;\n        update_need(id / N);\n    }\n\n    char decide_small(int d) const {\n        // Move all small cranes to column 4 at the beginning.\n        if (T < 4) return 'R';\n\n        const Crane &cr = cranes[d];\n\n        if (cr.hold != -1) {\n            if (cr.c < 4) return 'R';\n            return 'Q';\n        } else {\n            if (cr.c == 4) {\n                if (cont[d][handoff] == need[d]) return 'L';\n                return '.';\n            }\n            if (cr.c > handoff) {\n                if (cont[d][handoff] == need[d]) return 'L';\n                return 'R';\n            }\n            if (cr.c == handoff) {\n                if (cont[d][handoff] == need[d]) return 'P';\n                return 'R';\n            }\n            if (cr.c < 4) return 'R';\n            return '.';\n        }\n    }\n\n    void step_sim(const string &act) {\n        if (illegal) return;\n\n        // 1. arrivals\n        for (int r = 0; r < N; r++) {\n            if (arrival_idx[r] >= N) continue;\n            if (cont[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (!blocked) {\n                cont[r][0] = A[r][arrival_idx[r]];\n                arrival_idx[r]++;\n            }\n        }\n\n        array<pair<int,int>, N> oldp, newp;\n        for (int i = 0; i < N; i++) {\n            oldp[i] = {cranes[i].r, cranes[i].c};\n            newp[i] = oldp[i];\n        }\n\n        // pre-check actions\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) {\n                if (act[i] != '.') illegal = true;\n                continue;\n            }\n\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n\n            if (a == 'B') {\n                if (cranes[i].hold != -1) illegal = true;\n                continue;\n            }\n            if (a == 'P') {\n                if (cranes[i].hold != -1 || cont[r][c] == -1) illegal = true;\n                continue;\n            }\n            if (a == 'Q') {\n                if (cranes[i].hold == -1 || cont[r][c] != -1) illegal = true;\n                continue;\n            }\n            if (is_move(a)) {\n                int nr = r, nc = c;\n                if (a == 'U') nr--;\n                if (a == 'D') nr++;\n                if (a == 'L') nc--;\n                if (a == 'R') nc++;\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) illegal = true;\n                nr = max(0, min(N - 1, nr));\n                nc = max(0, min(N - 1, nc));\n\n                if (!cranes[i].large && cranes[i].hold != -1 && cont[nr][nc] != -1) {\n                    illegal = true;\n                }\n                newp[i] = {nr, nc};\n            }\n        }\n\n        // collisions / passing\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive || act[i] == 'B') continue;\n            for (int j = i + 1; j < N; j++) {\n                if (!cranes[j].alive || act[j] == 'B') continue;\n                if (newp[i] == newp[j]) illegal = true;\n                bool mi = (newp[i] != oldp[i]);\n                bool mj = (newp[j] != oldp[j]);\n                if (mi && mj && newp[i] == oldp[j] && newp[j] == oldp[i]) illegal = true;\n            }\n        }\n\n        if (illegal) return;\n\n        // bombs\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            if (act[i] == 'B') cranes[i].alive = false;\n        }\n\n        // moves\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            if (is_move(act[i])) {\n                cranes[i].r = newp[i].first;\n                cranes[i].c = newp[i].second;\n            }\n        }\n\n        // pick / drop\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n            if (a == 'P') {\n                cranes[i].hold = cont[r][c];\n                cont[r][c] = -1;\n            } else if (a == 'Q') {\n                cont[r][c] = cranes[i].hold;\n                cranes[i].hold = -1;\n            }\n        }\n\n        // 3. dispatch\n        for (int r = 0; r < N; r++) {\n            if (cont[r][4] != -1) {\n                dispatched[r].push_back(cont[r][4]);\n                cont[r][4] = -1;\n            }\n        }\n    }\n\n    void emit(char a0) {\n        if (illegal) return;\n\n        string act(N, '.');\n        act[0] = a0;\n        for (int i = 1; i < N; i++) act[i] = decide_small(i);\n\n        int small_pick_id[N];\n        int small_q_id[N];\n        for (int i = 0; i < N; i++) {\n            small_pick_id[i] = -1;\n            small_q_id[i] = -1;\n        }\n\n        for (int d = 1; d < N; d++) {\n            if (act[d] == 'P') small_pick_id[d] = cont[d][handoff];\n            if (act[d] == 'Q') small_q_id[d] = cranes[d].hold;\n        }\n\n        for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n        step_sim(act);\n        T++;\n\n        if (illegal) return;\n\n        for (int d = 1; d < N; d++) {\n            if (small_pick_id[d] != -1) {\n                int id = small_pick_id[d];\n                if (buffer_occ[d][handoff] == id) buffer_occ[d][handoff] = -1;\n                if (loc_type[id] == 1) buf_pos[id] = {-1, -1};\n            }\n            if (small_q_id[d] != -1) {\n                mark_done(small_q_id[d]);\n            }\n        }\n    }\n\n    // Avoid vertical travel on columns used by small cranes.\n    void move_to(int tr, int tc) {\n        int safe_col = handoff - 1;\n        int mid = min(tc, safe_col);\n\n        while (!illegal && cranes[0].c > mid) emit('L');\n        while (!illegal && cranes[0].c < mid) emit('R');\n        while (!illegal && cranes[0].r < tr) emit('D');\n        while (!illegal && cranes[0].r > tr) emit('U');\n        while (!illegal && cranes[0].c < tc) emit('R');\n        while (!illegal && cranes[0].c > tc) emit('L');\n    }\n\n    bool ready_id(int id) const {\n        if (id < 0 || id >= CNUM) return false;\n        if (done[id]) return false;\n        if (loc_type[id] == 1) return buf_pos[id].first != -1;\n        int s = src_of[id];\n        return pos_of[id] == idx[s];\n    }\n\n    vector<pair<int,int>> ordinary_slots() const {\n        vector<pair<int,int>> ret;\n\n        // col 1\n        for (int r = 0; r < N; r++) {\n            if (buffer_occ[r][1] == -1) ret.push_back({r, 1});\n        }\n\n        if (handoff == 3) {\n            for (int r = 0; r < N; r++) {\n                if (buffer_occ[r][2] == -1) ret.push_back({r, 2});\n            }\n            if (buffer_occ[0][3] == -1) ret.push_back({0, 3});\n        } else { // handoff == 2\n            if (buffer_occ[0][2] == -1) ret.push_back({0, 2});\n            if (buffer_occ[0][3] == -1) ret.push_back({0, 3});\n        }\n\n        for (int r = 0; r < N; r++) {\n            if (idx[r] == N && buffer_occ[r][0] == -1) {\n                ret.push_back({r, 0});\n            }\n        }\n        return ret;\n    }\n\n    vector<pair<int,int>> overflow_slots(int exclude_row = -1) const {\n        vector<pair<int,int>> ret;\n        for (int r = 1; r < N; r++) {\n            if (r == exclude_row) continue;\n            if (buffer_occ[r][3] != -1) continue;\n            if (row_pending_small(r)) continue;\n            ret.push_back({r, 3});\n        }\n        return ret;\n    }\n\n    pair<int,int> choose_slot(int src_row, int dest_row, bool allow_overflow = true, int exclude_overflow_row = -1) const {\n        pair<int,int> best = {-1, -1};\n        int best_score = INT_MAX;\n\n        auto eval = [&](int r, int c, int extra_penalty) {\n            int score = 0;\n            if (slot_policy == 0) {\n                // balanced\n                score += abs(src_row - r);\n                score += abs(r - dest_row);\n                score += c;\n                if (r == dest_row) score -= 2;\n                if (c == 1) score -= 1;\n            } else {\n                // source-biased\n                score += 2 * abs(src_row - r);\n                score += abs(r - dest_row);\n                score += c;\n                if (r == src_row) score -= 2;\n                if (r == dest_row) score -= 1;\n                if (c == 1) score -= 1;\n            }\n            score += extra_penalty;\n\n            if (score < best_score || (score == best_score && make_pair(r, c) < best)) {\n                best_score = score;\n                best = {r, c};\n            }\n        };\n\n        for (auto [r, c] : ordinary_slots()) eval(r, c, 0);\n        if (allow_overflow) {\n            for (auto [r, c] : overflow_slots(exclude_overflow_row)) eval(r, c, 6);\n        }\n        return best;\n    }\n\n    struct ReadyOpt {\n        int id = -1;\n        int cost = INT_MAX;\n    };\n\n    ReadyOpt choose_ready_opt() const {\n        ReadyOpt best;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (!ready_id(t)) continue;\n\n            pair<int,int> loc = (loc_type[t] == 1 ? buf_pos[t] : make_pair(src_of[t], 0));\n            int cost = mdist(cp, loc);\n            if (d == 0) cost += abs(loc.first - d) + (4 - loc.second);\n            else cost += abs(loc.first - d) + (handoff - loc.second);\n\n            if (d > 0 && handoff == 2 && buffer_occ[d][3] != -1) cost += 5;\n            if (d > 0 && handoff == 3 && buffer_occ[d][3] != -1 && buffer_occ[d][3] != t) cost += 5;\n\n            if (cost < best.cost || (cost == best.cost && t < best.id)) {\n                best.cost = cost;\n                best.id = t;\n            }\n        }\n        return best;\n    }\n\n    int choose_target_row() const {\n        int best_d = -1;\n        long long best_metric = (long long)4e18;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (ready_id(t)) continue;\n\n            int s = src_of[t];\n            int depth = pos_of[t] - idx[s];\n            int front = (idx[s] < N ? A[s][idx[s]] : INT_MAX);\n            int travel = abs(cp.first - s) + cp.second;\n            int align = abs(s - d);\n\n            long long metric;\n            if (policy == 0) {\n                metric = (((long long)depth) << 30) + (((long long)front) << 15) + (((long long)travel) << 7) + d;\n            } else if (policy == 1) {\n                metric = (((long long)depth) << 30) + (((long long)travel) << 15) + (((long long)front) << 7) + d;\n            } else {\n                metric = 10LL * depth + 2LL * travel + align;\n                metric = (metric << 10) + d;\n            }\n\n            if (metric < best_metric) {\n                best_metric = metric;\n                best_d = d;\n            }\n        }\n        return best_d;\n    }\n\n    struct BatchOpt {\n        int s = -1;\n        int target_id = -1;\n        int target_pos = -1;\n        int cost = INT_MAX;\n    };\n\n    BatchOpt choose_batch_opt() const {\n        BatchOpt best;\n        auto cp = cur_pos();\n\n        for (int s = 0; s < N; s++) {\n            if (idx[s] >= N) continue;\n\n            int best_pos = INT_MAX;\n            int best_id = -1;\n\n            for (int d = 0; d < N; d++) {\n                int t = need[d];\n                if (t > d * N + (N - 1)) continue;\n                if (assigned_row(d) && row_pending_small(d)) continue;\n                if (src_of[t] != s) continue;\n                if (pos_of[t] < idx[s]) continue;\n\n                if (pos_of[t] < best_pos || (pos_of[t] == best_pos && t < best_id)) {\n                    best_pos = pos_of[t];\n                    best_id = t;\n                }\n            }\n            if (best_id == -1) continue;\n\n            int depth = best_pos - idx[s];\n            int d = best_id / N;\n            int travel = abs(cp.first - s) + cp.second;\n            int deliver = (d == 0 ? abs(s - 0) + 4 : abs(s - d) + handoff);\n\n            int metric;\n            if (policy == 0) {\n                metric = 12 * depth + travel + deliver;\n            } else if (policy == 1) {\n                metric = 10 * depth + 2 * travel + deliver;\n            } else {\n                metric = 9 * depth + travel + 2 * deliver;\n            }\n\n            if (metric < best.cost || (metric == best.cost && make_tuple(depth, best_id, s) < make_tuple(best.target_pos == -1 ? INT_MAX : best.target_pos - idx[best.s], best.target_id, best.s))) {\n                best.cost = metric;\n                best.s = s;\n                best.target_id = best_id;\n                best.target_pos = best_pos;\n            }\n        }\n        return best;\n    }\n\n    void pick_id(int id) {\n        if (loc_type[id] == 1) {\n            auto [r, c] = buf_pos[id];\n            move_to(r, c);\n            if (illegal) return;\n            emit('P');\n            if (illegal) return;\n            buffer_occ[r][c] = -1;\n            loc_type[id] = 0;\n            buf_pos[id] = {-1, -1};\n        } else {\n            int s = src_of[id];\n            move_to(s, 0);\n            if (illegal) return;\n            emit('P');\n            if (illegal) return;\n            idx[s]++;\n        }\n    }\n\n    void direct_dispatch_large_row0(int id) {\n        move_to(0, 4);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        mark_done(id);\n    }\n\n    void clear_cell(int r, int c) {\n        int x = buffer_occ[r][c];\n        if (x == -1) return;\n        if (r >= 1 && row_pending_small(r)) return;\n\n        move_to(r, c);\n        if (illegal) return;\n        emit('P');\n        if (illegal) return;\n\n        buffer_occ[r][c] = -1;\n        loc_type[x] = 0;\n        buf_pos[x] = {-1, -1};\n\n        int d = x / N;\n\n        if (d == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (d > 0 && x == need[d] && !row_pending_small(d)) {\n            place_on_row_slot(x, d);\n            return;\n        }\n\n        auto slot = choose_slot(r, d, true, r);\n        if (slot.first == -1) {\n            // emergency fallback: direct correct gate\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(x);\n            return;\n        }\n\n        move_to(slot.first, slot.second);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void place_on_row_slot(int id, int d) {\n        if (d == 0) {\n            direct_dispatch_large_row0(id);\n            return;\n        }\n\n        if (handoff == 3) {\n            if (buffer_occ[d][3] != -1 && buffer_occ[d][3] != id) {\n                clear_cell(d, 3);\n                if (illegal) return;\n            }\n            if (buffer_occ[d][3] == -1) {\n                move_to(d, 3);\n                if (illegal) return;\n                emit('Q');\n                if (illegal) return;\n                loc_type[id] = 1;\n                buf_pos[id] = {d, 3};\n                buffer_occ[d][3] = id;\n            } else {\n                move_to(d, 4);\n                if (illegal) return;\n                emit('Q');\n                if (illegal) return;\n                mark_done(id);\n            }\n        } else { // handoff == 2\n            if (buffer_occ[d][3] != -1) {\n                clear_cell(d, 3);\n                if (illegal) return;\n            }\n            if (buffer_occ[d][2] != -1 && buffer_occ[d][2] != id) {\n                clear_cell(d, 2);\n                if (illegal) return;\n            }\n            if (buffer_occ[d][2] == -1 && buffer_occ[d][3] == -1) {\n                move_to(d, 2);\n                if (illegal) return;\n                emit('Q');\n                if (illegal) return;\n                loc_type[id] = 1;\n                buf_pos[id] = {d, 2};\n                buffer_occ[d][2] = id;\n            } else {\n                move_to(d, 4);\n                if (illegal) return;\n                emit('Q');\n                if (illegal) return;\n                mark_done(id);\n            }\n        }\n    }\n\n    void dispatch_ready(int id) {\n        pick_id(id);\n        if (illegal) return;\n        int d = id / N;\n        if (d == 0) direct_dispatch_large_row0(id);\n        else place_on_row_slot(id, d);\n    }\n\n    void buffer_or_handle_front(int s) {\n        int x = A[s][idx[s]];\n        move_to(s, 0);\n        if (illegal) return;\n        emit('P');\n        if (illegal) return;\n        idx[s]++;\n\n        int d = x / N;\n\n        if (d == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (d > 0 && x == need[d] && !row_pending_small(d)) {\n            place_on_row_slot(x, d);\n            return;\n        }\n\n        auto slot = choose_slot(s, d, true, -1);\n        if (slot.first == -1) {\n            // emergency fallback\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(x);\n            return;\n        }\n\n        move_to(slot.first, slot.second);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void process_source_batch(const BatchOpt &bo) {\n        int s = bo.s;\n        int target_pos = bo.target_pos;\n        while (!illegal && T < 10000 && idx[s] <= target_pos) {\n            int before = idx[s];\n            buffer_or_handle_front(s);\n            if (illegal) return;\n            if (idx[s] <= before) break;\n        }\n    }\n\n    long long exact_score() const {\n        if (illegal) return INF_SCORE;\n\n        long long M0 = T;\n        long long M1 = 0, M2 = 0, M3 = 0;\n\n        int total_dispatched = 0;\n        for (int r = 0; r < N; r++) {\n            vector<int> corr;\n            for (int x : dispatched[r]) {\n                total_dispatched++;\n                if (x / N != r) M2++;\n                else corr.push_back(x);\n            }\n            for (int i = 0; i < (int)corr.size(); i++) {\n                for (int j = i + 1; j < (int)corr.size(); j++) {\n                    if (corr[i] > corr[j]) M1++;\n                }\n            }\n        }\n        M3 = CNUM - total_dispatched;\n        return M0 + 100LL * M1 + 10000LL * M2 + 1000000LL * M3;\n    }\n\n    void init() {\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int x = A[r][j];\n                src_of[x] = r;\n                pos_of[x] = j;\n            }\n        }\n        for (int d = 0; d < N; d++) need[d] = d * N;\n\n        for (int i = 0; i < N; i++) {\n            cranes[i].alive = true;\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].hold = -1;\n            cranes[i].large = (i == 0);\n        }\n    }\n\n    Result solve() {\n        init();\n\n        // Move small cranes to column 4.\n        for (int k = 0; k < 4 && !illegal; k++) emit('.');\n\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            if (mode == 0) {\n                ReadyOpt ro = choose_ready_opt();\n                if (ro.id != -1) {\n                    dispatch_ready(ro.id);\n                    continue;\n                }\n\n                int d = choose_target_row();\n                if (d == -1) {\n                    bool pending = false;\n                    for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n                    if (pending) {\n                        if (cranes[0].c > handoff - 1) emit('L');\n                        else emit('.');\n                        continue;\n                    }\n                    break;\n                }\n\n                int t = need[d];\n                int s = src_of[t];\n                if (idx[s] >= N) break;\n                buffer_or_handle_front(s);\n            } else {\n                ReadyOpt ro = choose_ready_opt();\n                BatchOpt bo = choose_batch_opt();\n\n                if (bo.s == -1) {\n                    if (ro.id != -1) {\n                        dispatch_ready(ro.id);\n                        continue;\n                    }\n                    bool pending = false;\n                    for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n                    if (pending) {\n                        if (cranes[0].c > handoff - 1) emit('L');\n                        else emit('.');\n                        continue;\n                    }\n                    break;\n                }\n\n                bool take_ready = false;\n                if (ro.id != -1) {\n                    if (ro.cost <= bo.cost + ready_bias) take_ready = true;\n                }\n\n                if (take_ready) dispatch_ready(ro.id);\n                else process_source_batch(bo);\n            }\n        }\n\n        // Drain pending small-crane deliveries.\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            bool pending = false;\n            for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n            if (!pending) break;\n            if (cranes[0].c > handoff - 1) emit('L');\n            else emit('.');\n        }\n\n        // Safety fallback.\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            ReadyOpt ro = choose_ready_opt();\n            if (ro.id != -1) {\n                dispatch_ready(ro.id);\n                continue;\n            }\n\n            bool progressed = false;\n            for (int s = 0; s < N && !progressed; s++) {\n                if (idx[s] < N) {\n                    buffer_or_handle_front(s);\n                    progressed = true;\n                }\n            }\n            if (progressed) continue;\n\n            bool pending = false;\n            for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n            if (pending) {\n                if (cranes[0].c > handoff - 1) emit('L');\n                else emit('.');\n                continue;\n            }\n            break;\n        }\n\n        if (out[0].empty()) {\n            for (int i = 0; i < N; i++) out[i] = \".\";\n        }\n\n        Result res;\n        res.score = exact_score();\n        res.out = out;\n        return res;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n;\n    cin >> n;\n    int A[N][N];\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) cin >> A[i][j];\n    }\n\n    struct Variant {\n        int handoff, mode, policy, ready_bias, slot_policy;\n    };\n\n    vector<Variant> vars = {\n        // previous-style greedy portfolio\n        {3, 0, 0, 0, 0},\n        {3, 0, 1, 0, 0},\n        {2, 0, 1, 0, 0},\n        {2, 0, 2, 0, 0},\n        {3, 0, 2, 0, 1},\n        {2, 0, 2, 0, 1},\n\n        // new source-batch portfolio\n        {3, 1, 0, 0, 1},\n        {3, 1, 1, 2, 1},\n        {3, 1, 1, 6, 1},\n        {2, 1, 0, 0, 1},\n        {2, 1, 1, 2, 1},\n        {2, 1, 1, 6, 1},\n    };\n\n    Result best;\n    for (auto v : vars) {\n        Planner planner(A, v.handoff, v.mode, v.policy, v.ready_bias, v.slot_policy);\n        Result cur = planner.solve();\n        if (cur.score < best.score) best = cur;\n    }\n\n    if (best.out.empty()) {\n        for (int i = 0; i < N; i++) cout << \".\\n\";\n    } else {\n        for (int i = 0; i < N; i++) cout << best.out[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int r, c;\n};\n\nstruct EvalInfo {\n    long long cost;\n    int borrow;\n};\n\nstruct Candidate {\n    long long cost;\n    int borrow;\n    vector<int> path;\n};\n\nstruct State {\n    vector<int> path;\n    vector<int> pos;\n    long long cost;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    int next_int(int n) { return (int)(next_u32() % (uint32_t)n); }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n};\n\nstatic constexpr long long INF64 = (1LL << 62);\n\nint N, M;\nvector<int> H1;\nlong long BASE_COST = 0;\n\nint rr_[400], cc_[400];\nint dist0_[400];\nint distmat_[400][400];\nbool adjmat_[400][400];\nvector<int> neigh_[400];\n\nchrono::steady_clock::time_point TIME_BEGIN;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - TIME_BEGIN).count();\n}\n\ninline bool better_eval(const EvalInfo& a, const EvalInfo& b) {\n    if (a.cost != b.cost) return a.cost < b.cost;\n    return a.borrow < b.borrow;\n}\n\nPoint apply_sym(Point p, int sym, int N) {\n    if (sym >= 4) {\n        p.c = N - 1 - p.c;\n        sym -= 4;\n    }\n    for (int k = 0; k < sym; k++) {\n        int nr = p.c;\n        int nc = N - 1 - p.r;\n        p.r = nr;\n        p.c = nc;\n    }\n    return p;\n}\n\nvector<Point> transform_order(const vector<Point>& base, int sym, bool rev, int N) {\n    vector<Point> v;\n    v.reserve(base.size());\n    for (auto p : base) v.push_back(apply_sym(p, sym, N));\n    if (rev) reverse(v.begin(), v.end());\n    return v;\n}\n\nbool validate_order(const vector<Point>& ord, int N, bool cycle) {\n    if ((int)ord.size() != N * N) return false;\n    vector<int> seen(N * N, 0);\n    for (auto p : ord) {\n        if (p.r < 0 || p.r >= N || p.c < 0 || p.c >= N) return false;\n        int id = p.r * N + p.c;\n        if (seen[id]) return false;\n        seen[id] = 1;\n    }\n    for (int i = 0; i + 1 < (int)ord.size(); i++) {\n        int d = abs(ord[i].r - ord[i + 1].r) + abs(ord[i].c - ord[i + 1].c);\n        if (d != 1) return false;\n    }\n    if (cycle) {\n        int d = abs(ord.back().r - ord.front().r) + abs(ord.back().c - ord.front().c);\n        if (d != 1) return false;\n    }\n    return true;\n}\n\nvector<Point> make_base_cycle(int N) {\n    vector<Point> cyc;\n    cyc.reserve(N * N);\n\n    for (int r = 0; r < N; r++) cyc.push_back({r, 0});\n\n    for (int c = 1; c < N; c++) {\n        if (c & 1) {\n            for (int r = N - 1; r >= 1; r--) cyc.push_back({r, c});\n        } else {\n            for (int r = 1; r < N; r++) cyc.push_back({r, c});\n        }\n    }\n\n    cyc.push_back({0, N - 1});\n    for (int c = N - 2; c >= 1; c--) cyc.push_back({0, c});\n\n    return cyc;\n}\n\nvector<Point> make_row_snake(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    for (int r = 0; r < N; r++) {\n        if ((r & 1) == 0) {\n            for (int c = 0; c < N; c++) ord.push_back({r, c});\n        } else {\n            for (int c = N - 1; c >= 0; c--) ord.push_back({r, c});\n        }\n    }\n    return ord;\n}\n\nvector<Point> make_spiral(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\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++) ord.push_back({top, c});\n        top++;\n        for (int r = top; r <= bottom; r++) ord.push_back({r, right});\n        right--;\n        if (top <= bottom) {\n            for (int c = right; c >= left; c--) ord.push_back({bottom, c});\n            bottom--;\n        }\n        if (left <= right) {\n            for (int r = bottom; r >= top; r--) ord.push_back({r, left});\n            left++;\n        }\n    }\n    return ord;\n}\n\nint sgn(int x) { return (x > 0) - (x < 0); }\n\nvoid gilbert2d(int x, int y, int ax, int ay, int bx, int by, vector<Point>& out) {\n    int w = abs(ax + ay);\n    int h = abs(bx + by);\n\n    int dax = sgn(ax), day = sgn(ay);\n    int dbx = sgn(bx), dby = sgn(by);\n\n    if (h == 1) {\n        for (int i = 0; i < w; i++) {\n            out.push_back({y, x});\n            x += dax;\n            y += day;\n        }\n        return;\n    }\n    if (w == 1) {\n        for (int i = 0; i < h; i++) {\n            out.push_back({y, x});\n            x += dbx;\n            y += dby;\n        }\n        return;\n    }\n\n    int ax2 = ax / 2, ay2 = ay / 2;\n    int bx2 = bx / 2, by2 = by / 2;\n\n    int w2 = abs(ax2 + ay2);\n    int h2 = abs(bx2 + by2);\n\n    if (2 * w > 3 * h) {\n        if ((w2 & 1) && (w > 2)) {\n            ax2 += dax;\n            ay2 += day;\n        }\n        gilbert2d(x, y, ax2, ay2, bx, by, out);\n        gilbert2d(x + ax2, y + ay2, ax - ax2, ay - ay2, bx, by, out);\n    } else {\n        if ((h2 & 1) && (h > 2)) {\n            bx2 += dbx;\n            by2 += dby;\n        }\n        gilbert2d(x, y, bx2, by2, ax2, ay2, out);\n        gilbert2d(x + bx2, y + by2, ax, ay, bx - bx2, by - by2, out);\n        gilbert2d(\n            x + (ax - dax) + (bx2 - dbx),\n            y + (ay - day) + (by2 - dby),\n            -bx2, -by2, -(ax - ax2), -(ay - ay2), out\n        );\n    }\n}\n\nvector<Point> make_gilbert(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    gilbert2d(0, 0, N, 0, 0, N, ord);\n    return ord;\n}\n\nvector<int> points_to_ids(const vector<Point>& v) {\n    vector<int> ids;\n    ids.reserve(v.size());\n    for (auto p : v) ids.push_back(p.r * N + p.c);\n    return ids;\n}\n\nvoid build_pos(const vector<int>& path, vector<int>& pos) {\n    pos.assign(M, -1);\n    for (int i = 0; i < M; i++) pos[path[i]] = i;\n}\n\nEvalInfo eval_path_direction(const vector<int>& path, bool rev) {\n    long long cur = 0, min_pref = 0, sum_pref = 0;\n    if (!rev) {\n        for (int i = 0; i < M; i++) {\n            cur += H1[path[i]];\n            if (cur < min_pref) min_pref = cur;\n            if (i + 1 < M) sum_pref += cur;\n        }\n        long long k = -min_pref;\n        int s = path[0], t = path[M - 1];\n        int ret = (k > 0 ? distmat_[s][t] : 0);\n        long long cost =\n            BASE_COST +\n            2LL * k +\n            100LL * (dist0_[s] + (M - 1) + ret) +\n            sum_pref +\n            k * 1LL * ((M - 1) + ret);\n        return {cost, (int)k};\n    } else {\n        for (int i = M - 1; i >= 0; i--) {\n            cur += H1[path[i]];\n            if (cur < min_pref) min_pref = cur;\n            if (i > 0) sum_pref += cur;\n        }\n        long long k = -min_pref;\n        int s = path[M - 1], t = path[0];\n        int ret = (k > 0 ? distmat_[s][t] : 0);\n        long long cost =\n            BASE_COST +\n            2LL * k +\n            100LL * (dist0_[s] + (M - 1) + ret) +\n            sum_pref +\n            k * 1LL * ((M - 1) + ret);\n        return {cost, (int)k};\n    }\n}\n\npair<EvalInfo, int> eval_cycle_best_shift(const vector<int>& cyc) {\n    static long long P[405];\n    static long long pref[410];\n\n    P[0] = 0;\n    for (int i = 0; i < M; i++) P[i + 1] = P[i] + H1[cyc[i]];\n\n    long long minP = P[0];\n    for (int st = 1; st < M; st++) minP = min(minP, P[st]);\n\n    pref[0] = 0;\n    for (int i = 0; i <= M; i++) pref[i + 1] = pref[i] + P[i];\n\n    EvalInfo best{INF64, 0};\n    int best_st = 0;\n\n    for (int st = 0; st < M; st++) {\n        if (P[st] != minP) continue;\n\n        long long sum1 = pref[M + 1] - pref[st + 1];\n        long long sum2 = (st >= 2 ? pref[st] - pref[1] : 0);\n        long long carry = sum1 + sum2 - 1LL * (M - 1) * P[st];\n\n        int s = cyc[st];\n        long long cost = BASE_COST + 100LL * (dist0_[s] + (M - 1)) + carry;\n        EvalInfo cur{cost, 0};\n        if (better_eval(cur, best)) {\n            best = cur;\n            best_st = st;\n        }\n    }\n    return {best, best_st};\n}\n\nvoid orient_best_inplace(vector<int>& path, EvalInfo& best_eval) {\n    EvalInfo best = eval_path_direction(path, false);\n    int mode = 0; // 0:fwd path, 1:rev path, 2:cycle cut fwd, 3:cycle cut rev\n    int best_st = 0;\n\n    EvalInfo revp = eval_path_direction(path, true);\n    if (better_eval(revp, best)) {\n        best = revp;\n        mode = 1;\n    }\n\n    if (adjmat_[path.front()][path.back()]) {\n        auto [cycf, stf] = eval_cycle_best_shift(path);\n        if (better_eval(cycf, best)) {\n            best = cycf;\n            mode = 2;\n            best_st = stf;\n        }\n\n        vector<int> rev_path = path;\n        reverse(rev_path.begin(), rev_path.end());\n        auto [cycr, str] = eval_cycle_best_shift(rev_path);\n        if (better_eval(cycr, best)) {\n            best = cycr;\n            mode = 3;\n            best_st = str;\n        }\n    }\n\n    if (mode == 1) {\n        reverse(path.begin(), path.end());\n    } else if (mode == 2) {\n        rotate(path.begin(), path.begin() + best_st, path.end());\n    } else if (mode == 3) {\n        reverse(path.begin(), path.end());\n        rotate(path.begin(), path.begin() + best_st, path.end());\n    }\n\n    best_eval = best;\n}\n\nuint64_t hash_order(const vector<int>& path) {\n    uint64_t h = 1469598103934665603ull;\n    for (int x : path) {\n        h ^= (uint64_t)(x + 1);\n        h *= 1099511628211ull;\n    }\n    return h;\n}\n\nbool random_backbite(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    int first_side = rng.next_int(2);\n    for (int rep = 0; rep < 2; rep++) {\n        int side = first_side ^ rep;\n        if (side == 0) {\n            int ep = path[0];\n            int forbidden = path[1];\n            int cand[4], cnt = 0;\n            for (int u : neigh_[ep]) {\n                if (u != forbidden) cand[cnt++] = u;\n            }\n            if (cnt == 0) continue;\n            int u = cand[rng.next_int(cnt)];\n            int i = pos[u];\n            if (i <= 1) continue;\n            reverse(path.begin(), path.begin() + i);\n            for (int k = 0; k < i; k++) pos[path[k]] = k;\n            return true;\n        } else {\n            int ep = path[M - 1];\n            int forbidden = path[M - 2];\n            int cand[4], cnt = 0;\n            for (int u : neigh_[ep]) {\n                if (u != forbidden) cand[cnt++] = u;\n            }\n            if (cnt == 0) continue;\n            int u = cand[rng.next_int(cnt)];\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            reverse(path.begin() + i + 1, path.end());\n            for (int k = i + 1; k < M; k++) pos[path[k]] = k;\n            return true;\n        }\n    }\n    return false;\n}\n\nbool random_two_opt(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    for (int tries = 0; tries < 32; tries++) {\n        int i = rng.next_int(M - 1);\n        int a = path[i];\n        int b = path[i + 1];\n        int prev = (i > 0 ? path[i - 1] : -1);\n\n        int candj[4], cnt = 0;\n        for (int u : neigh_[a]) {\n            if (u == b || u == prev) continue;\n            int j = pos[u];\n            if (j <= i + 1) continue;\n            if (j == M - 1 || adjmat_[b][path[j + 1]]) {\n                if (!(i == 0 && j == M - 1)) candj[cnt++] = j;\n            }\n        }\n        if (cnt == 0) continue;\n\n        int j = candj[rng.next_int(cnt)];\n        reverse(path.begin() + i + 1, path.begin() + j + 1);\n        for (int k = i + 1; k <= j; k++) pos[path[k]] = k;\n        return true;\n    }\n    return false;\n}\n\nbool mutate_path(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    int t = rng.next_int(100);\n    if (t < 55) {\n        if (random_backbite(path, pos, rng)) return true;\n        return random_two_opt(path, pos, rng);\n    } else {\n        if (random_two_opt(path, pos, rng)) return true;\n        return random_backbite(path, pos, rng);\n    }\n}\n\nbool best_improving_move(vector<int>& path, vector<int>& pos, EvalInfo& cur_ev, double deadline_sec) {\n    EvalInfo best = cur_ev;\n    vector<int> best_path;\n    bool found = false;\n\n    auto consider = [&](vector<int>& cand) {\n        EvalInfo ev;\n        orient_best_inplace(cand, ev);\n        if (better_eval(ev, best)) {\n            best = ev;\n            best_path = cand;\n            found = true;\n        }\n    };\n\n    // backbite from front\n    {\n        int ep = path[0];\n        int forbidden = path[1];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i <= 1) continue;\n            vector<int> cand = path;\n            reverse(cand.begin(), cand.begin() + i);\n            consider(cand);\n        }\n    }\n\n    // backbite from back\n    {\n        int ep = path[M - 1];\n        int forbidden = path[M - 2];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.end());\n            consider(cand);\n        }\n    }\n\n    // exhaustive valid 2-opt-like reversals\n    for (int i = 0; i < M - 1; i++) {\n        if ((i & 31) == 0 && elapsed_sec() > deadline_sec) break;\n\n        int a = path[i];\n        int b = path[i + 1];\n        int prev = (i > 0 ? path[i - 1] : -1);\n\n        for (int u : neigh_[a]) {\n            if (u == b || u == prev) continue;\n            int j = pos[u];\n            if (j <= i + 1) continue;\n            if (i == 0 && j == M - 1) continue;\n            if (j != M - 1 && !adjmat_[b][path[j + 1]]) continue;\n\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.begin() + j + 1);\n            consider(cand);\n        }\n    }\n\n    if (found && better_eval(best, cur_ev)) {\n        path.swap(best_path);\n        build_pos(path, pos);\n        cur_ev = best;\n        return true;\n    }\n    return false;\n}\n\nvoid greedy_local_opt(vector<int>& path, EvalInfo& ev, int max_steps, double deadline_sec) {\n    orient_best_inplace(path, ev);\n    vector<int> pos;\n    build_pos(path, pos);\n\n    for (int step = 0; step < max_steps; step++) {\n        if (elapsed_sec() > deadline_sec) break;\n        if (!best_improving_move(path, pos, ev, deadline_sec)) break;\n    }\n}\n\nchar dir_between(int a, int b) {\n    if (rr_[b] == rr_[a] + 1 && cc_[b] == cc_[a]) return 'D';\n    if (rr_[b] == rr_[a] - 1 && cc_[b] == cc_[a]) return 'U';\n    if (rr_[b] == rr_[a] && cc_[b] == cc_[a] + 1) return 'R';\n    return 'L';\n}\n\nvoid move_manhattan(int& cr, int& cc, int tr, int tc, vector<string>& ans) {\n    while (cr < tr) ans.push_back(\"D\"), cr++;\n    while (cr > tr) ans.push_back(\"U\"), cr--;\n    while (cc < tc) ans.push_back(\"R\"), cc++;\n    while (cc > tc) ans.push_back(\"L\"), cc--;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    TIME_BEGIN = chrono::steady_clock::now();\n\n    cin >> N;\n    M = N * N;\n\n    vector<vector<int>> h(N, vector<int>(N));\n    H1.assign(M, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> h[i][j];\n            int id = i * N + j;\n            H1[id] = h[i][j];\n            BASE_COST += llabs((long long)h[i][j]);\n        }\n    }\n\n    if (BASE_COST == 0) {\n        return 0;\n    }\n\n    for (int id = 0; id < M; id++) {\n        rr_[id] = id / N;\n        cc_[id] = id % N;\n        dist0_[id] = rr_[id] + cc_[id];\n    }\n    for (int a = 0; a < M; a++) {\n        neigh_[a].clear();\n        for (int b = 0; b < M; b++) {\n            distmat_[a][b] = abs(rr_[a] - rr_[b]) + abs(cc_[a] - cc_[b]);\n            adjmat_[a][b] = (distmat_[a][b] == 1);\n        }\n        int r = rr_[a], c = cc_[a];\n        if (r > 0) neigh_[a].push_back((r - 1) * N + c);\n        if (r + 1 < N) neigh_[a].push_back((r + 1) * N + c);\n        if (c > 0) neigh_[a].push_back(r * N + (c - 1));\n        if (c + 1 < N) neigh_[a].push_back(r * N + (c + 1));\n    }\n\n    uint64_t seed = 0x9e3779b97f4a7c15ull;\n    for (int i = 0; i < M; i++) {\n        seed ^= (uint64_t)(H1[i] + 128 + 1009 * i);\n        seed ^= seed << 13;\n        seed ^= seed >> 7;\n        seed ^= seed << 17;\n    }\n    XorShift64 rng(seed);\n\n    vector<Point> cyc0 = make_base_cycle(N);\n    vector<Point> snake0 = make_row_snake(N);\n    vector<Point> spiral0 = make_spiral(N);\n    vector<Point> gilbert0 = make_gilbert(N);\n\n    vector<vector<Point>> base_cycles;\n    vector<vector<Point>> base_paths;\n\n    if (validate_order(cyc0, N, true)) base_cycles.push_back(cyc0);\n    if (validate_order(snake0, N, false)) base_paths.push_back(snake0);\n    if (validate_order(spiral0, N, false)) base_paths.push_back(spiral0);\n    if (validate_order(gilbert0, N, false)) base_paths.push_back(gilbert0);\n\n    vector<Candidate> pool;\n    pool.reserve(128);\n\n    for (auto& bc : base_cycles) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto ordp = transform_order(bc, sym, rev, N);\n                if (!validate_order(ordp, N, true)) continue;\n                auto ids = points_to_ids(ordp);\n                auto [ev, st] = eval_cycle_best_shift(ids);\n                rotate(ids.begin(), ids.begin() + st, ids.end());\n                pool.push_back({ev.cost, ev.borrow, move(ids)});\n            }\n        }\n    }\n\n    for (auto& bp : base_paths) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto ordp = transform_order(bp, sym, rev, N);\n                if (!validate_order(ordp, N, false)) continue;\n                auto ids = points_to_ids(ordp);\n                EvalInfo ev;\n                orient_best_inplace(ids, ev);\n                pool.push_back({ev.cost, ev.borrow, move(ids)});\n            }\n        }\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.borrow < b.borrow;\n    });\n\n    Candidate global_best = pool[0];\n\n    auto update_global = [&](const vector<int>& path, const EvalInfo& ev) {\n        EvalInfo cur{global_best.cost, global_best.borrow};\n        if (better_eval(ev, cur)) {\n            global_best.cost = ev.cost;\n            global_best.borrow = ev.borrow;\n            global_best.path = path;\n        }\n    };\n\n    vector<vector<int>> seeds;\n    unordered_set<uint64_t> used;\n    used.reserve(512);\n\n    for (auto& cand : pool) {\n        uint64_t hs = hash_order(cand.path);\n        if (used.insert(hs).second) {\n            seeds.push_back(cand.path);\n            if ((int)seeds.size() >= 12) break;\n        }\n    }\n    for (int idx : {16, 24, 36, 48}) {\n        if (idx < (int)pool.size()) {\n            uint64_t hs = hash_order(pool[idx].path);\n            if (used.insert(hs).second) seeds.push_back(pool[idx].path);\n        }\n    }\n    if (seeds.empty()) seeds.push_back(global_best.path);\n\n    const double TOTAL_TL = 1.92;\n    const double SA_END = 1.68;\n\n    // Pre-polish a few seeds.\n    for (int i = 0; i < (int)seeds.size() && i < 6; i++) {\n        if (elapsed_sec() > 0.35) break;\n        EvalInfo ev;\n        greedy_local_opt(seeds[i], ev, 8, 0.35);\n        update_global(seeds[i], ev);\n    }\n\n    auto make_state = [&](const vector<int>& base_path, int perturb_steps) -> State {\n        State st;\n        st.path = base_path;\n        build_pos(st.path, st.pos);\n\n        for (int t = 0; t < perturb_steps; t++) {\n            mutate_path(st.path, st.pos, rng);\n        }\n\n        EvalInfo ev;\n        orient_best_inplace(st.path, ev);\n        build_pos(st.path, st.pos);\n\n        if (elapsed_sec() < 0.65) {\n            greedy_local_opt(st.path, ev, 3, 0.65);\n            build_pos(st.path, st.pos);\n        }\n\n        st.cost = ev.cost;\n        update_global(st.path, ev);\n        return st;\n    };\n\n    vector<State> states;\n    for (int i = 0; i < (int)seeds.size() && i < 8; i++) {\n        states.push_back(make_state(seeds[i], 0));\n    }\n    for (int i = 0; i < (int)seeds.size() && i < 8; i++) {\n        states.push_back(make_state(seeds[i], 16 + 8 * i));\n    }\n    if (states.empty()) {\n        states.push_back(make_state(global_best.path, 0));\n    }\n\n    double next_restart = 0.34;\n\n    while (elapsed_sec() < SA_END) {\n        int idx = rng.next_int((int)states.size());\n        State& cur = states[idx];\n\n        vector<int> cand_path = cur.path;\n        vector<int> cand_pos = cur.pos;\n\n        int kicks = 1 + (rng.next_int(100) < 20 ? 2 : 0);\n        bool ok = false;\n        for (int t = 0; t < kicks; t++) {\n            ok |= mutate_path(cand_path, cand_pos, rng);\n        }\n        if (!ok) continue;\n\n        EvalInfo cand_ev;\n        orient_best_inplace(cand_path, cand_ev);\n\n        double frac = elapsed_sec() / SA_END;\n        double T0 = 1800.0, T1 = 10.0;\n        double temp = T0 * pow(T1 / T0, frac);\n\n        bool accept = false;\n        if (cand_ev.cost <= cur.cost) {\n            accept = true;\n        } else {\n            double prob = exp((double)(cur.cost - cand_ev.cost) / temp);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.path.swap(cand_path);\n            build_pos(cur.path, cur.pos);\n            cur.cost = cand_ev.cost;\n\n            EvalInfo gcur{global_best.cost, global_best.borrow};\n            if (better_eval(cand_ev, gcur) && elapsed_sec() < SA_END - 0.05) {\n                greedy_local_opt(cur.path, cand_ev, 2, SA_END - 0.01);\n                build_pos(cur.path, cur.pos);\n                cur.cost = cand_ev.cost;\n            }\n            update_global(cur.path, cand_ev);\n        }\n\n        if (elapsed_sec() >= next_restart && elapsed_sec() < SA_END - 0.08) {\n            int worst = 0;\n            for (int i = 1; i < (int)states.size(); i++) {\n                if (states[i].cost > states[worst].cost) worst = i;\n            }\n            states[worst] = make_state(global_best.path, 24 + rng.next_int(24));\n            next_restart += 0.34;\n        }\n    }\n\n    // Final deterministic intensification.\n    {\n        EvalInfo ev{global_best.cost, global_best.borrow};\n        vector<int> path = global_best.path;\n        greedy_local_opt(path, ev, 50, TOTAL_TL - 0.10);\n        update_global(path, ev);\n    }\n\n    // A few kick-and-polish rounds near the end.\n    while (elapsed_sec() < TOTAL_TL - 0.02) {\n        vector<int> cand = global_best.path;\n        vector<int> pos;\n        build_pos(cand, pos);\n\n        int kick = 3 + rng.next_int(6);\n        for (int t = 0; t < kick; t++) mutate_path(cand, pos, rng);\n\n        EvalInfo ev;\n        orient_best_inplace(cand, ev);\n        greedy_local_opt(cand, ev, 10, TOTAL_TL - 0.01);\n        update_global(cand, ev);\n    }\n\n    // Final polish on the final best.\n    {\n        EvalInfo ev{global_best.cost, global_best.borrow};\n        vector<int> path = global_best.path;\n        greedy_local_opt(path, ev, 20, TOTAL_TL - 0.005);\n        update_global(path, ev);\n    }\n\n    vector<string> ans;\n    ans.reserve(3000);\n\n    int cr = 0, cc = 0;\n    int start_id = global_best.path.front();\n    move_manhattan(cr, cc, rr_[start_id], cc_[start_id], ans);\n\n    if (global_best.borrow > 0) {\n        ans.push_back(\"+\" + to_string(global_best.borrow));\n    }\n\n    for (int i = 0; i < M; i++) {\n        int id = global_best.path[i];\n        int v = H1[id];\n        if (v > 0) ans.push_back(\"+\" + to_string(v));\n        else if (v < 0) ans.push_back(\"-\" + to_string(-v));\n\n        if (i + 1 < M) {\n            char d = dir_between(global_best.path[i], global_best.path[i + 1]);\n            ans.push_back(string(1, d));\n        }\n    }\n\n    if (global_best.borrow > 0) {\n        int end_id = global_best.path.back();\n        cr = rr_[end_id];\n        cc = cc_[end_id];\n        move_manhattan(cr, cc, rr_[start_id], cc_[start_id], ans);\n        ans.push_back(\"-\" + to_string(global_best.borrow));\n    }\n\n    for (auto& s : ans) {\n        cout << s << '\\n';\n    }\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Seed {\n    array<int, 15> x{};\n    int value = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, T;\n    int S, P;\n\n    vector<Seed> seeds;\n\n    vector<vector<int>> adj;\n    vector<pair<int, int>> edges;\n    vector<int> deg;\n    vector<int> posOrder;\n    vector<int> blackPos, whitePos;\n\n    mt19937_64 rng;\n\n    // Per-turn data\n    array<double, 15> rareW{};\n    vector<ll> weightedSeedValue;\n    vector<vector<int>> evalQ; // candidate meta evaluation edge score\n\n    Solver(int N_, int M_, int T_)\n        : N(N_), M(M_), T(T_), S(2 * N_ * (N_ - 1)), P(N_ * N_),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        buildGrid();\n    }\n\n    void buildGrid() {\n        adj.assign(P, {});\n        deg.assign(P, 0);\n        edges.clear();\n        blackPos.clear();\n        whitePos.clear();\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                if (((r + c) & 1) == 0) blackPos.push_back(p);\n                else whitePos.push_back(p);\n\n                if (c + 1 < N) {\n                    int q = r * N + (c + 1);\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n                if (r + 1 < N) {\n                    int q = (r + 1) * N + c;\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n            }\n        }\n        for (int p = 0; p < P; p++) deg[p] = (int)adj[p].size();\n\n        vector<pair<array<int, 5>, int>> ord;\n        ord.reserve(P);\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                int dist = abs(2 * r - (N - 1)) + abs(2 * c - (N - 1));\n                ord.push_back({{dist, -deg[p], ((r + c) & 1), r, c}, p});\n            }\n        }\n        sort(ord.begin(), ord.end());\n        posOrder.clear();\n        for (auto &e : ord) posOrder.push_back(e.second);\n    }\n\n    bool readSeeds() {\n        seeds.assign(S, Seed());\n        for (int i = 0; i < S; i++) {\n            int sum = 0;\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> seeds[i].x[j])) return false;\n                sum += seeds[i].x[j];\n            }\n            seeds[i].value = sum;\n        }\n        return true;\n    }\n\n    void buildTurnStatistics(int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1); // early 1, late 0\n\n        array<int, 15> best1{}, best2{}, cntNear{};\n        for (int l = 0; l < M; l++) {\n            int mx1 = -1, mx2 = -1;\n            for (int i = 0; i < S; i++) {\n                int v = seeds[i].x[l];\n                if (v > mx1) {\n                    mx2 = mx1;\n                    mx1 = v;\n                } else if (v > mx2) {\n                    mx2 = v;\n                }\n            }\n            int cnt = 0;\n            for (int i = 0; i < S; i++) {\n                if (seeds[i].x[l] >= mx1 - 1) cnt++;\n            }\n            best1[l] = mx1;\n            best2[l] = max(0, mx2);\n            cntNear[l] = max(1, cnt);\n        }\n\n        double sumW = 0.0;\n        for (int l = 0; l < M; l++) {\n            double scarcity = 1.0 / cntNear[l];\n            double gapRatio = (double)(best1[l] - best2[l]) / max(1, best1[l]);\n            double w = 1.0 + (0.55 * scarcity + 0.90 * gapRatio) * (0.25 + 1.35 * g);\n            rareW[l] = w;\n            sumW += w;\n        }\n        double norm = (double)M / sumW;\n        for (int l = 0; l < M; l++) rareW[l] *= norm;\n\n        weightedSeedValue.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            double s = 0.0;\n            for (int l = 0; l < M; l++) s += rareW[l] * seeds[i].x[l];\n            weightedSeedValue[i] = (ll)llround(100.0 * s);\n        }\n\n        evalQ.assign(S, vector<int>(S, 0));\n        double betaEval = 1.65 + 0.20 * (1.0 - g);\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0;\n                double mean = 0.5 * (seeds[i].value + seeds[j].value);\n                double diff2 = 0.0;\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    opt += max(a, b);\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n                }\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + betaEval * sigma);\n                int v = (int)llround(q * 100.0);\n                evalQ[i][j] = evalQ[j][i] = v;\n            }\n        }\n    }\n\n    vector<vector<ll>> makeScoreMatrix(int scheme, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n        double alphaBalanced = 0.25 + 0.45 * g;\n        double alphaRare = 0.35 + 0.40 * g;\n        double beta = 1.45 + 0.30 * (1.0 - g);\n\n        vector<vector<ll>> sc(S, vector<ll>(S, 0));\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0, mean = 0.5 * (seeds[i].value + seeds[j].value), diff2 = 0.0;\n                double optw = 0.0, meanw = 0.0, diffw2 = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    int mx = max(a, b);\n\n                    opt += mx;\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n\n                    optw += rareW[l] * mx;\n                    meanw += 0.5 * rareW[l] * (a + b);\n                    double dw = rareW[l] * d;\n                    diffw2 += dw * dw;\n                }\n\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + beta * sigma);\n\n                double sigmaw = 0.5 * sqrt(diffw2);\n                double qw = min(optw, meanw + beta * sigmaw);\n\n                double val = 0.0;\n                switch (scheme) {\n                    case 0: // balanced\n                        val = alphaBalanced * opt + (1.0 - alphaBalanced) * q;\n                        break;\n                    case 1: // rarity-aware balanced\n                        val = alphaRare * optw + (1.0 - alphaRare) * qw;\n                        break;\n                    case 2: // pure optimistic\n                        val = opt;\n                        break;\n                    case 3: // pure realistic\n                        val = q;\n                        break;\n                    case 4: // rarity-aware realistic\n                        val = qw;\n                        break;\n                    case 5: // late-only convexified realistic, emphasizes strong edges\n                        val = q * q / 1000.0;\n                        break;\n                    default:\n                        val = q;\n                        break;\n                }\n\n                ll iv = (ll)llround(val * 100.0);\n                sc[i][j] = sc[j][i] = iv;\n            }\n        }\n\n        return sc;\n    }\n\n    vector<ll> computeIndividualPotential(const vector<vector<ll>>& sc, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n        int K = min(5, S - 1);\n\n        vector<ll> ind(S, 0);\n        vector<ll> tmp;\n        tmp.reserve(S - 1);\n\n        for (int i = 0; i < S; i++) {\n            tmp.clear();\n            for (int j = 0; j < S; j++) {\n                if (i == j) continue;\n                tmp.push_back(sc[i][j]);\n            }\n            if (K < (int)tmp.size()) {\n                nth_element(tmp.begin(), tmp.begin() + K, tmp.end(), greater<ll>());\n            }\n            ll sumTop = 0;\n            for (int k = 0; k < K; k++) sumTop += tmp[k];\n\n            ll bias = 25LL * seeds[i].value + (ll)llround((12.0 + 18.0 * g) * (weightedSeedValue[i] / 100.0));\n            ind[i] = sumTop / K + bias;\n        }\n        return ind;\n    }\n\n    vector<int> initAssignment(const vector<vector<ll>>& sc, const vector<ll>& ind, int mode, int noiseScale) {\n        vector<int> assign(P, -1);\n        vector<char> used(S, false);\n\n        if (mode == 1) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                return weightedSeedValue[a] > weightedSeedValue[b];\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        if (mode == 2) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (ind[a] != ind[b]) return ind[a] > ind[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        if (mode == 3) {\n            array<int, 15> bestNow{};\n            bestNow.fill(0);\n\n            for (int idx = 0; idx < P; idx++) {\n                ll bestScore = LLONG_MIN;\n                int bestSeed = -1;\n\n                for (int s = 0; s < S; s++) if (!used[s]) {\n                    ll gain = 0;\n                    for (int l = 0; l < M; l++) {\n                        int v = seeds[s].x[l];\n                        if (v > bestNow[l]) {\n                            gain += (ll)llround(100.0 * rareW[l] * (v - bestNow[l]));\n                        }\n                    }\n                    ll score = gain + weightedSeedValue[s] / 6 + 20LL * seeds[s].value;\n                    if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                    if (score > bestScore || (score == bestScore && (rng() & 1ULL))) {\n                        bestScore = score;\n                        bestSeed = s;\n                    }\n                }\n\n                assign[posOrder[idx]] = bestSeed;\n                used[bestSeed] = true;\n                for (int l = 0; l < M; l++) bestNow[l] = max(bestNow[l], seeds[bestSeed].x[l]);\n            }\n            return assign;\n        }\n\n        if (mode == 4) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (weightedSeedValue[a] != weightedSeedValue[b]) return weightedSeedValue[a] > weightedSeedValue[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        // greedy\n        for (int p : posOrder) {\n            int fixedCnt = 0;\n            for (int nb : adj[p]) if (assign[nb] != -1) fixedCnt++;\n\n            ll bestSc = LLONG_MIN;\n            int bestSeed = -1;\n\n            for (int s = 0; s < S; s++) if (!used[s]) {\n                ll score = 1LL * (deg[p] - fixedCnt) * ind[s];\n                for (int nb : adj[p]) {\n                    if (assign[nb] != -1) score += sc[s][assign[nb]];\n                }\n                if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                if (score > bestSc || (score == bestSc && (rng() & 1ULL))) {\n                    bestSc = score;\n                    bestSeed = s;\n                }\n            }\n\n            assign[p] = bestSeed;\n            used[bestSeed] = true;\n        }\n\n        return assign;\n    }\n\n    ll calcObjective(const vector<int>& assign, const vector<vector<ll>>& sc) const {\n        ll res = 0;\n        for (auto [u, v] : edges) res += sc[assign[u]][assign[v]];\n        return res;\n    }\n\n    // Hungarian for max weight assignment, n <= m\n    vector<int> hungarianMax(const vector<vector<ll>>& a) const {\n        int n = (int)a.size();\n        int m = (int)a[0].size();\n        const ll INF = (1LL << 60);\n\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF;\n\n                for (int j = 1; j <= m; j++) if (!used[j]) {\n                    ll cur = -a[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    void optimizeColor(vector<int>& assign, const vector<vector<ll>>& sc,\n                       const vector<int>& group, const vector<int>& other) {\n        vector<char> banned(S, false);\n        for (int p : other) banned[assign[p]] = true;\n\n        vector<int> cand;\n        cand.reserve(S - (int)other.size());\n        for (int s = 0; s < S; s++) {\n            if (!banned[s]) cand.push_back(s);\n        }\n\n        int n = (int)group.size();\n        int m = (int)cand.size();\n        vector<vector<ll>> benefit(n, vector<ll>(m, 0));\n\n        for (int i = 0; i < n; i++) {\n            int p = group[i];\n            for (int j = 0; j < m; j++) {\n                int s = cand[j];\n                ll b = 0;\n                for (int nb : adj[p]) b += sc[s][assign[nb]];\n                benefit[i][j] = b;\n            }\n        }\n\n        vector<int> choice = hungarianMax(benefit);\n        for (int i = 0; i < n; i++) {\n            assign[group[i]] = cand[choice[i]];\n        }\n    }\n\n    ll coordinateAscent(vector<int>& assign, const vector<vector<ll>>& sc) {\n        ll obj = calcObjective(assign, sc);\n        for (int it = 0; it < 8; it++) {\n            ll old = obj;\n            optimizeColor(assign, sc, blackPos, whitePos);\n            optimizeColor(assign, sc, whitePos, blackPos);\n            obj = calcObjective(assign, sc);\n            if (obj <= old) break;\n        }\n        return obj;\n    }\n\n    ll deltaSwap(const vector<int>& assign, const vector<vector<ll>>& sc, int p, int q) const {\n        if (p == q) return 0;\n        int a = assign[p];\n        int b = assign[q];\n        ll d = 0;\n\n        for (int nb : adj[p]) {\n            if (nb == q) continue;\n            d += sc[b][assign[nb]] - sc[a][assign[nb]];\n        }\n        for (int nb : adj[q]) {\n            if (nb == p) continue;\n            d += sc[a][assign[nb]] - sc[b][assign[nb]];\n        }\n        return d;\n    }\n\n    ll crossSwapImprove(vector<int>& assign, const vector<vector<ll>>& sc, ll obj) {\n        for (int pass = 0; pass < 6; pass++) {\n            ll bestDelta = 0;\n            int bestB = -1, bestW = -1;\n\n            for (int p : blackPos) {\n                for (int q : whitePos) {\n                    ll d = deltaSwap(assign, sc, p, q);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bestB = p;\n                        bestW = q;\n                    }\n                }\n            }\n\n            if (bestDelta <= 0) break;\n\n            swap(assign[bestB], assign[bestW]);\n            obj = coordinateAscent(assign, sc);\n        }\n        return obj;\n    }\n\n    ll evaluateCandidate(const vector<int>& assign, int remTurns) const {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n\n        vector<int> qvals;\n        qvals.reserve(edges.size());\n        ll totalQ = 0;\n\n        vector<array<int, 15>> virt(edges.size());\n        array<int, 15> top1{}, top2{}, top3{};\n        top1.fill(0);\n        top2.fill(0);\n        top3.fill(0);\n\n        int ei = 0;\n        for (auto [u, v] : edges) {\n            int a = assign[u], b = assign[v];\n            int q = evalQ[a][b];\n            qvals.push_back(q);\n            totalQ += q;\n\n            for (int l = 0; l < M; l++) {\n                int mv = max(seeds[a].x[l], seeds[b].x[l]);\n                virt[ei][l] = mv;\n                if (mv >= top1[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = top1[l];\n                    top1[l] = mv;\n                } else if (mv >= top2[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = mv;\n                } else if (mv > top3[l]) {\n                    top3[l] = mv;\n                }\n            }\n            ei++;\n        }\n\n        sort(qvals.begin(), qvals.end(), greater<int>());\n        static const int W[10] = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55};\n\n        ll weightedTop = 0;\n        for (int i = 0; i < min<int>(10, qvals.size()); i++) {\n            weightedTop += 1LL * qvals[i] * W[i];\n        }\n        weightedTop /= 100;\n\n        double c2 = 0.45 + 0.25 * g;\n        double c3 = 0.20 * g;\n        double coverage = 0.0;\n        for (int l = 0; l < M; l++) {\n            coverage += top1[l] + c2 * top2[l] + c3 * top3[l];\n        }\n\n        int bestFuture = 0;\n        if (remTurns >= 2) {\n            for (int i = 0; i < (int)virt.size(); i++) {\n                for (int j = i + 1; j < (int)virt.size(); j++) {\n                    int s = 0;\n                    for (int l = 0; l < M; l++) s += max(virt[i][l], virt[j][l]);\n                    if (s > bestFuture) bestFuture = s;\n                }\n            }\n        }\n\n        ll meta = 0;\n        meta += weightedTop;\n        meta += totalQ / 50;\n        meta += (ll)llround((25.0 + 80.0 * g) * coverage);\n        if (remTurns >= 2) meta += (ll)llround((15.0 + 70.0 * g) * bestFuture);\n\n        return meta;\n    }\n\n    double exactExpectedMaxLastTurn(const vector<int>& assign) const {\n        const int MAXSUM = 1500;\n        static double prodCDF[1501];\n        static double buf1[1501];\n        static double buf2[1501];\n\n        for (int s = 0; s <= MAXSUM; s++) prodCDF[s] = 1.0;\n\n        for (auto [u, v] : edges) {\n            int aId = assign[u];\n            int bId = assign[v];\n\n            double* dp = buf1;\n            double* ndp = buf2;\n            for (int s = 0; s <= MAXSUM; s++) dp[s] = 0.0;\n            dp[0] = 1.0;\n            int curMax = 0;\n\n            for (int l = 0; l < M; l++) {\n                int a = seeds[aId].x[l];\n                int b = seeds[bId].x[l];\n                int nextMax = curMax + max(a, b);\n                for (int s = 0; s <= nextMax; s++) ndp[s] = 0.0;\n\n                if (a == b) {\n                    for (int s = 0; s <= curMax; s++) {\n                        ndp[s + a] += dp[s];\n                    }\n                } else {\n                    for (int s = 0; s <= curMax; s++) {\n                        double half = 0.5 * dp[s];\n                        ndp[s + a] += half;\n                        ndp[s + b] += half;\n                    }\n                }\n\n                curMax = nextMax;\n                swap(dp, ndp);\n            }\n\n            double cdf = 0.0;\n            for (int s = 0; s <= curMax; s++) {\n                cdf += dp[s];\n                prodCDF[s] *= cdf;\n            }\n        }\n\n        double ans = 0.0;\n        for (int s = 1; s <= MAXSUM; s++) {\n            ans += 1.0 - prodCDF[s - 1];\n        }\n        return ans;\n    }\n\n    static uint64_t splitmix64(uint64_t x) {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        return x ^ (x >> 31);\n    }\n\n    uint64_t hashAssign(const vector<int>& assign) const {\n        uint64_t h = 0x123456789abcdef0ULL;\n        for (int v : assign) {\n            h ^= splitmix64((uint64_t)v + h);\n            h = (h << 7) | (h >> 57);\n        }\n        return h;\n    }\n\n    vector<int> decideLayout(int turn) {\n        int remTurns = T - turn;\n        buildTurnStatistics(remTurns);\n\n        struct Candidate {\n            vector<int> assign;\n            ll meta;\n        };\n\n        vector<Candidate> cands;\n        unordered_set<uint64_t> seen;\n        seen.reserve(256);\n\n        int schemeCount = 5;\n        if (remTurns == 1) schemeCount = 6;\n\n        for (int s = 0; s < schemeCount; s++) {\n            vector<vector<ll>> sc = makeScoreMatrix(s, remTurns);\n            vector<ll> ind = computeIndividualPotential(sc, remTurns);\n\n            vector<pair<int, int>> starts = {\n                {0, 0},\n                {1, 0},\n                {2, 0},\n                {3, 0},\n                {4, 0},\n                {0, 15000}\n            };\n\n            if (remTurns <= 2) {\n                starts.push_back({0, 30000});\n                starts.push_back({3, 8000});\n            }\n\n            for (auto [mode, noise] : starts) {\n                vector<int> assign = initAssignment(sc, ind, mode, noise);\n                ll obj = coordinateAscent(assign, sc);\n                obj = crossSwapImprove(assign, sc, obj);\n                (void)obj;\n\n                uint64_t h = hashAssign(assign);\n                if (!seen.insert(h).second) continue;\n\n                ll meta = evaluateCandidate(assign, remTurns);\n                cands.push_back({assign, meta});\n            }\n        }\n\n        // Normal turns: deterministic surrogate selection\n        if (remTurns >= 2) {\n            ll bestMeta = LLONG_MIN;\n            vector<int> bestAssign = cands[0].assign;\n            for (auto &c : cands) {\n                if (c.meta > bestMeta) {\n                    bestMeta = c.meta;\n                    bestAssign = c.assign;\n                }\n            }\n            return bestAssign;\n        }\n\n        // Last turn: exact expected maximum among candidates\n        double bestE = -1e100;\n        ll bestMeta = LLONG_MIN;\n        vector<int> bestAssign = cands[0].assign;\n\n        for (auto &c : cands) {\n            double e = exactExpectedMaxLastTurn(c.assign);\n            if (e > bestE + 1e-12 || (abs(e - bestE) <= 1e-12 && c.meta > bestMeta)) {\n                bestE = e;\n                bestMeta = c.meta;\n                bestAssign = c.assign;\n            }\n        }\n        return bestAssign;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    Solver solver(N, M, T);\n    if (!solver.readSeeds()) return 0;\n\n    for (int t = 0; t < T; t++) {\n        vector<int> assign = solver.decideLayout(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << assign[i * N + j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (!solver.readSeeds()) return 0;\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Block {\n    bool pickup;           // true: source block, false: target block\n    vector<int> ids;       // indices in src/dst\n};\n\nstruct Plan {\n    int startIdx = 0;\n    int h = 1;\n    long long est = (1LL << 60); // rough estimate\n    string key;\n    vector<Block> blocks;\n};\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nint N, M, Vcap;\nvector<Pt> src, dst;\nint Qm;\nvector<vector<unsigned short>> SS, ST, TS, TT;\nvector<vector<int>> srcIdAt, dstIdAt;\n\nstatic inline int dist_by_type(bool curIsSource, int curIdx, bool toSource, int toIdx) {\n    if (curIsSource) {\n        return toSource ? SS[curIdx][toIdx] : ST[curIdx][toIdx];\n    } else {\n        return toSource ? TS[curIdx][toIdx] : TT[curIdx][toIdx];\n    }\n}\n\nvector<int> make_start_candidates() {\n    vector<int> cand;\n    vector<char> used(Qm, false);\n    auto add = [&](int idx) {\n        if (0 <= idx && idx < Qm && !used[idx]) {\n            used[idx] = true;\n            cand.push_back(idx);\n        }\n    };\n\n    const int ALL_START_THRESHOLD = 180;\n    if (Qm <= ALL_START_THRESHOLD) {\n        for (int i = 0; i < Qm; i++) add(i);\n        return cand;\n    }\n\n    int minX = 0, maxX = 0, minY = 0, maxY = 0;\n    int minS = 0, maxS = 0, minD = 0, maxD = 0;\n    for (int i = 1; i < Qm; i++) {\n        if (src[i].x < src[minX].x) minX = i;\n        if (src[i].x > src[maxX].x) maxX = i;\n        if (src[i].y < src[minY].y) minY = i;\n        if (src[i].y > src[maxY].y) maxY = i;\n        if (src[i].x + src[i].y < src[minS].x + src[minS].y) minS = i;\n        if (src[i].x + src[i].y > src[maxS].x + src[maxS].y) maxS = i;\n        if (src[i].x - src[i].y < src[minD].x - src[minD].y) minD = i;\n        if (src[i].x - src[i].y > src[maxD].x - src[maxD].y) maxD = i;\n    }\n    add(minX); add(maxX); add(minY); add(maxY);\n    add(minS); add(maxS); add(minD); add(maxD);\n\n    vector<Pt> corners = {{0,0}, {0,N-1}, {N-1,0}, {N-1,N-1}};\n    for (auto c : corners) {\n        int best = 0, bestd = manhattan(src[0], c);\n        for (int i = 1; i < Qm; i++) {\n            int d = manhattan(src[i], c);\n            if (d < bestd) bestd = d, best = i;\n        }\n        add(best);\n    }\n\n    double cx = 0, cy = 0;\n    for (auto &p : src) cx += p.x, cy += p.y;\n    cx /= Qm; cy /= Qm;\n    int nearC = 0, farC = 0;\n    double bestNear = 1e100, bestFar = -1.0;\n    for (int i = 0; i < Qm; i++) {\n        double dx = src[i].x - cx;\n        double dy = src[i].y - cy;\n        double v = dx * dx + dy * dy;\n        if (v < bestNear) bestNear = v, nearC = i;\n        if (v > bestFar) bestFar = v, farC = i;\n    }\n    add(nearC); add(farC);\n\n    vector<int> ord(Qm);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int va = src[a].x + src[a].y, vb = src[b].x + src[b].y;\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    add(ord[0]); add(ord[Qm / 4]); add(ord[Qm / 2]); add(ord[(3 * Qm) / 4]); add(ord[Qm - 1]);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int va = src[a].x - src[a].y, vb = src[b].x - src[b].y;\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    add(ord[0]); add(ord[Qm / 4]); add(ord[Qm / 2]); add(ord[(3 * Qm) / 4]); add(ord[Qm - 1]);\n\n    if (cand.empty()) add(0);\n    return cand;\n}\n\nPlan make_batch_plan(int h, int startIdx) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.key = \"B:\" + to_string(h) + \":\" + to_string(startIdx);\n    plan.est = 2;\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    bool curIsSource = true;\n    int curIdx = startIdx;\n    int load = 1;\n\n    while (!remS.empty() || load > 0) {\n        Block b1{true, {}};\n        while (load < h && !remS.empty()) {\n            int bestPos = -1, bestId = -1, bestDist = INT_MAX;\n            for (int pos = 0; pos < (int)remS.size(); pos++) {\n                int id = remS[pos];\n                int d = dist_by_type(curIsSource, curIdx, true, id);\n                if (d < bestDist) {\n                    bestDist = d;\n                    bestPos = pos;\n                    bestId = id;\n                }\n            }\n            plan.est += bestDist;\n            curIsSource = true;\n            curIdx = bestId;\n            load++;\n            b1.ids.push_back(bestId);\n            remS[bestPos] = remS.back();\n            remS.pop_back();\n        }\n        if (!b1.ids.empty()) plan.blocks.push_back(move(b1));\n\n        Block b2{false, {}};\n        while (load > 0) {\n            int bestPos = -1, bestId = -1, bestDist = INT_MAX;\n            for (int pos = 0; pos < (int)remT.size(); pos++) {\n                int id = remT[pos];\n                int d = dist_by_type(curIsSource, curIdx, false, id);\n                if (d < bestDist) {\n                    bestDist = d;\n                    bestPos = pos;\n                    bestId = id;\n                }\n            }\n            plan.est += bestDist;\n            curIsSource = false;\n            curIdx = bestId;\n            load--;\n            b2.ids.push_back(bestId);\n            remT[bestPos] = remT.back();\n            remT.pop_back();\n        }\n        if (!b2.ids.empty()) plan.blocks.push_back(move(b2));\n    }\n    return plan;\n}\n\ntemplate<class DistFunc>\nvector<pair<int,int>> topK_indices(const vector<int>& rem, DistFunc distf, int K) {\n    vector<pair<int,int>> best; // {dist, pos}\n    best.reserve(K);\n    for (int pos = 0; pos < (int)rem.size(); pos++) {\n        int d = distf(rem[pos]);\n        if ((int)best.size() < K) {\n            best.push_back({d, pos});\n            int i = (int)best.size() - 1;\n            while (i > 0 && best[i] < best[i - 1]) {\n                swap(best[i], best[i - 1]);\n                --i;\n            }\n        } else if (d < best.back().first) {\n            best.back() = {d, pos};\n            int i = K - 1;\n            while (i > 0 && best[i] < best[i - 1]) {\n                swap(best[i], best[i - 1]);\n                --i;\n            }\n        }\n    }\n    return best;\n}\n\nint nearest_after_action(bool candIsSource, int candIdx, bool wantSource,\n                         const vector<int>& remS, const vector<int>& remT, int skipId) {\n    int best = INT_MAX;\n    if (wantSource) {\n        for (int id : remS) {\n            if (candIsSource && id == skipId) continue;\n            int d = dist_by_type(candIsSource, candIdx, true, id);\n            if (d < best) best = d;\n        }\n    } else {\n        for (int id : remT) {\n            if (!candIsSource && id == skipId) continue;\n            int d = dist_by_type(candIsSource, candIdx, false, id);\n            if (d < best) best = d;\n        }\n    }\n    return best;\n}\n\nPlan make_balanced_plan(int h, int startIdx, int alpha, int gamma, int topK, int stayBonus) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.key = \"G:\" + to_string(h) + \":\" + to_string(startIdx) + \":\" +\n               to_string(alpha) + \":\" + to_string(gamma) + \":\" + to_string(topK) + \":\" + to_string(stayBonus);\n    plan.est = 2;\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    bool curIsSource = true;\n    int curIdx = startIdx;\n    int load = 1;\n    int prevType = 1; // source\n\n    while (!remS.empty() || load > 0) {\n        vector<tuple<long long,int,int,bool>> cands; // {eval, pos, dist, isSource}\n        cands.reserve(2 * topK);\n\n        if (load < h && !remS.empty()) {\n            auto bestS = topK_indices(remS, [&](int id) {\n                return dist_by_type(curIsSource, curIdx, true, id);\n            }, topK);\n\n            for (auto [d, pos] : bestS) {\n                int id = remS[pos];\n                int load2 = load + 1;\n                int ns = nearest_after_action(true, id, true, remS, remT, id);\n                int nt = nearest_after_action(true, id, false, remS, remT, -1);\n\n                long long future = 0;\n                if (load2 == 0) {\n                    future = (ns == INT_MAX ? 0 : ns);\n                } else if (load2 == h) {\n                    future = (nt == INT_MAX ? 0 : nt);\n                } else {\n                    long long a = (ns == INT_MAX ? (long long)4e18 : (long long)ns + alpha * max(0, 2 * load2 - h));\n                    long long b = (nt == INT_MAX ? (long long)4e18 : (long long)nt + alpha * max(0, h - 2 * load2));\n                    future = min(a, b);\n                    if (future > (long long)3e18) future = 0;\n                }\n                long long eval = (long long)d + (long long)gamma * future;\n                if (prevType == 1) eval -= stayBonus;\n                cands.emplace_back(eval, pos, d, true);\n            }\n        }\n\n        if (load > 0 && !remT.empty()) {\n            auto bestT = topK_indices(remT, [&](int id) {\n                return dist_by_type(curIsSource, curIdx, false, id);\n            }, topK);\n\n            for (auto [d, pos] : bestT) {\n                int id = remT[pos];\n                int load2 = load - 1;\n                int ns = nearest_after_action(false, id, true, remS, remT, -1);\n                int nt = nearest_after_action(false, id, false, remS, remT, id);\n\n                long long future = 0;\n                if (load2 == 0) {\n                    future = (ns == INT_MAX ? 0 : ns);\n                } else if (load2 == h) {\n                    future = (nt == INT_MAX ? 0 : nt);\n                } else {\n                    long long a = (ns == INT_MAX ? (long long)4e18 : (long long)ns + alpha * max(0, 2 * load2 - h));\n                    long long b = (nt == INT_MAX ? (long long)4e18 : (long long)nt + alpha * max(0, h - 2 * load2));\n                    future = min(a, b);\n                    if (future > (long long)3e18) future = 0;\n                }\n                long long eval = (long long)d + (long long)gamma * future;\n                if (prevType == 0) eval -= stayBonus;\n                cands.emplace_back(eval, pos, d, false);\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [&](auto& A, auto& B) {\n            if (get<0>(A) != get<0>(B)) return get<0>(A) < get<0>(B);\n            if (get<2>(A) != get<2>(B)) return get<2>(A) < get<2>(B);\n            return get<3>(A) > get<3>(B);\n        });\n\n        if (cands.empty()) break;\n\n        auto [eval, pos, d, isSource] = cands[0];\n        plan.est += d;\n\n        if (plan.blocks.empty() || plan.blocks.back().pickup != isSource) {\n            plan.blocks.push_back(Block{isSource, {}});\n        }\n\n        if (isSource) {\n            int id = remS[pos];\n            plan.blocks.back().ids.push_back(id);\n            remS[pos] = remS.back();\n            remS.pop_back();\n            curIsSource = true;\n            curIdx = id;\n            load++;\n            prevType = 1;\n        } else {\n            int id = remT[pos];\n            plan.blocks.back().ids.push_back(id);\n            remT[pos] = remT.back();\n            remT.pop_back();\n            curIsSource = false;\n            curIdx = id;\n            load--;\n            prevType = 0;\n        }\n    }\n\n    return plan;\n}\n\nstruct ExecResult {\n    long long cost = (1LL << 60);\n    vector<string> ops;\n};\n\nint path_gain_dp(const Pt& a, const Pt& b, bool pickup, const vector<char>& mark) {\n    static int dp[31][31];\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) dp[i][j] = -1e9;\n    }\n    dp[0][0] = 0;\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && mark[idx]) add = 1;\n            int best = -1e9;\n            if (i > 0) best = max(best, dp[i - 1][j]);\n            if (j > 0) best = max(best, dp[i][j - 1]);\n            dp[i][j] = best + add;\n        }\n    }\n    return dp[dx][dy];\n}\n\nvector<char> reconstruct_best_path(const Pt& a, const Pt& b, bool pickup, const vector<char>& mark) {\n    static int dp[31][31];\n    static char par[31][31];\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            dp[i][j] = -1e9;\n            par[i][j] = '?';\n        }\n    }\n    dp[0][0] = 0;\n    par[0][0] = '.';\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && mark[idx]) add = 1;\n\n            int best = -1e9;\n            char bp = '?';\n            if (i > 0) {\n                int cand = dp[i - 1][j] + add;\n                if (cand > best) best = cand, bp = 'V';\n            }\n            if (j > 0) {\n                int cand = dp[i][j - 1] + add;\n                if (cand > best) best = cand, bp = 'H';\n            }\n            dp[i][j] = best;\n            par[i][j] = bp;\n        }\n    }\n\n    vector<char> rev;\n    int i = dx, j = dy;\n    while (!(i == 0 && j == 0)) {\n        if (par[i][j] == 'V') {\n            rev.push_back(sx == 1 ? 'D' : 'U');\n            --i;\n        } else {\n            rev.push_back(sy == 1 ? 'R' : 'L');\n            --j;\n        }\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nExecResult execute_plan(const Plan& plan, bool buildOps, int Vp, int leafCount) {\n    ExecResult res;\n    if (buildOps) res.ops.clear();\n\n    auto make_cmd = [&]() -> string {\n        return string(2 * Vp, '.');\n    };\n\n    Pt cur = src[plan.startIdx];\n    int load = 1;\n    long long steps = 0;\n\n    vector<int> holding(leafCount, 0);\n    if (leafCount > 0) holding[0] = 1;\n\n    if (buildOps) {\n        string cmd0 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd0[u] = 'R';\n        res.ops.push_back(cmd0);\n\n        string cmd1 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd1[u] = 'R';\n        cmd1[Vp + 2] = 'P';\n        res.ops.push_back(cmd1);\n    }\n\n    for (const auto& block : plan.blocks) {\n        vector<char> mark(Qm, 0);\n        int rem = 0;\n        for (int id : block.ids) {\n            mark[id] = 1;\n            rem++;\n        }\n\n        while (rem > 0) {\n            int bestId = -1;\n            int bestGain = -1;\n            int bestDist = INT_MAX;\n\n            for (int id : block.ids) if (mark[id]) {\n                const Pt& p = block.pickup ? src[id] : dst[id];\n                int g = path_gain_dp(cur, p, block.pickup, mark);\n                int d = manhattan(cur, p);\n                if (g > bestGain || (g == bestGain && d < bestDist)) {\n                    bestGain = g;\n                    bestDist = d;\n                    bestId = id;\n                }\n            }\n\n            const Pt& dest = block.pickup ? src[bestId] : dst[bestId];\n            vector<char> moves = reconstruct_best_path(cur, dest, block.pickup, mark);\n\n            for (char mv : moves) {\n                if (mv == 'U') cur.x--;\n                else if (mv == 'D') cur.x++;\n                else if (mv == 'L') cur.y--;\n                else if (mv == 'R') cur.y++;\n\n                steps++;\n                string cmd;\n                if (buildOps) cmd = make_cmd();\n                if (buildOps) cmd[0] = mv;\n\n                int idx = block.pickup ? srcIdAt[cur.x][cur.y] : dstIdAt[cur.x][cur.y];\n                if (idx != -1 && mark[idx]) {\n                    mark[idx] = 0;\n                    rem--;\n                    if (block.pickup) {\n                        load++;\n                        if (buildOps) {\n                            int chosen = -1;\n                            for (int i = 0; i < leafCount; i++) {\n                                if (!holding[i]) {\n                                    chosen = i;\n                                    holding[i] = 1;\n                                    break;\n                                }\n                            }\n                            if (chosen == -1) chosen = 0;\n                            int vertex = 2 + chosen;\n                            cmd[Vp + vertex] = 'P';\n                        }\n                    } else {\n                        load--;\n                        if (buildOps) {\n                            int chosen = -1;\n                            for (int i = 0; i < leafCount; i++) {\n                                if (holding[i]) {\n                                    chosen = i;\n                                    holding[i] = 0;\n                                    break;\n                                }\n                            }\n                            if (chosen == -1) chosen = 0;\n                            int vertex = 2 + chosen;\n                            cmd[Vp + vertex] = 'P';\n                        }\n                    }\n                }\n\n                if (buildOps) res.ops.push_back(move(cmd));\n            }\n        }\n    }\n\n    if (load != 0) {\n        res.cost = (1LL << 60);\n        return res;\n    }\n    res.cost = 2 + steps;\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> Vcap;\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    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (s[i][j] == '1' && t[i][j] == '0') src.push_back({i, j});\n            else if (s[i][j] == '0' && t[i][j] == '1') dst.push_back({i, j});\n        }\n    }\n\n    Qm = (int)src.size();\n    const int Vp = Vcap;\n    const int leafCount = Vp - 2;\n\n    auto output_tree = [&](int root_x, int root_y) {\n        cout << Vp << '\\n';\n        cout << 0 << ' ' << 1 << '\\n';\n        for (int u = 2; u < Vp; u++) {\n            cout << 1 << ' ' << 1 << '\\n';\n        }\n        cout << root_x << ' ' << root_y << '\\n';\n    };\n\n    if (Qm == 0) {\n        output_tree(0, 0);\n        return 0;\n    }\n\n    SS.assign(Qm, vector<unsigned short>(Qm));\n    ST.assign(Qm, vector<unsigned short>(Qm));\n    TS.assign(Qm, vector<unsigned short>(Qm));\n    TT.assign(Qm, vector<unsigned short>(Qm));\n    for (int i = 0; i < Qm; i++) {\n        for (int j = 0; j < Qm; j++) {\n            SS[i][j] = (unsigned short)manhattan(src[i], src[j]);\n            ST[i][j] = (unsigned short)manhattan(src[i], dst[j]);\n            TS[i][j] = (unsigned short)manhattan(dst[i], src[j]);\n            TT[i][j] = (unsigned short)manhattan(dst[i], dst[j]);\n        }\n    }\n\n    srcIdAt.assign(N, vector<int>(N, -1));\n    dstIdAt.assign(N, vector<int>(N, -1));\n    for (int i = 0; i < Qm; i++) {\n        srcIdAt[src[i].x][src[i].y] = i;\n        dstIdAt[dst[i].x][dst[i].y] = i;\n    }\n\n    vector<int> startCandidates = make_start_candidates();\n    int maxH = min(leafCount, Qm);\n\n    // 1) Generate batch candidates\n    vector<Plan> batchPlans;\n    batchPlans.reserve((int)startCandidates.size() * maxH);\n    for (int h = 1; h <= maxH; h++) {\n        for (int st : startCandidates) {\n            batchPlans.push_back(make_batch_plan(h, st));\n        }\n    }\n    sort(batchPlans.begin(), batchPlans.end(), [](const Plan& a, const Plan& b) {\n        if (a.est != b.est) return a.est < b.est;\n        return a.key < b.key;\n    });\n\n    vector<Plan> finalCandidates;\n    unordered_set<string> usedKey;\n\n    auto add_candidate = [&](const Plan& p) {\n        if (usedKey.insert(p.key).second) finalCandidates.push_back(p);\n    };\n\n    // best batch per h\n    for (int h = 1; h <= maxH; h++) {\n        long long best = (1LL << 60);\n        int bestPos = -1;\n        for (int i = 0; i < (int)batchPlans.size(); i++) {\n            if (batchPlans[i].h == h && batchPlans[i].est < best) {\n                best = batchPlans[i].est;\n                bestPos = i;\n            }\n        }\n        if (bestPos != -1) add_candidate(batchPlans[bestPos]);\n    }\n\n    // top batch overall\n    for (int i = 0; i < min(8, (int)batchPlans.size()); i++) {\n        add_candidate(batchPlans[i]);\n    }\n\n    // 2) Generate balanced candidates from top batch seeds\n    vector<pair<int,int>> seeds; // {start,h}\n    {\n        unordered_set<long long> seen;\n        for (int i = 0; i < min(6, (int)batchPlans.size()); i++) {\n            long long key = (long long)batchPlans[i].startIdx * 100 + batchPlans[i].h;\n            if (seen.insert(key).second) seeds.push_back({batchPlans[i].startIdx, batchPlans[i].h});\n        }\n    }\n\n    vector<Plan> balancedPlans;\n    for (auto [st, h0] : seeds) {\n        vector<int> hs = {h0, max(1, h0 - 1), min(maxH, h0 + 1), maxH, max(1, maxH / 2)};\n        sort(hs.begin(), hs.end());\n        hs.erase(unique(hs.begin(), hs.end()), hs.end());\n        for (int h : hs) {\n            for (int alpha : {0, 2, 4, 8}) {\n                for (int gamma : {0, 1, 2}) {\n                    for (int stayBonus : {0, 2}) {\n                        balancedPlans.push_back(make_balanced_plan(h, st, alpha, gamma, 3, stayBonus));\n                    }\n                }\n            }\n        }\n    }\n    sort(balancedPlans.begin(), balancedPlans.end(), [](const Plan& a, const Plan& b) {\n        if (a.est != b.est) return a.est < b.est;\n        return a.key < b.key;\n    });\n    for (int i = 0; i < min(14, (int)balancedPlans.size()); i++) {\n        add_candidate(balancedPlans[i]);\n    }\n\n    // 3) Exact evaluation with path-aware block optimization\n    long long bestCost = (1LL << 60);\n    int bestIdx = -1;\n\n    vector<long long> exactCost(finalCandidates.size(), (1LL << 60));\n    for (int i = 0; i < (int)finalCandidates.size(); i++) {\n        auto r = execute_plan(finalCandidates[i], false, Vp, leafCount);\n        exactCost[i] = r.cost;\n        if (r.cost < bestCost) {\n            bestCost = r.cost;\n            bestIdx = i;\n        }\n    }\n\n    // Build final ops\n    ExecResult bestRes = execute_plan(finalCandidates[bestIdx], true, Vp, leafCount);\n\n    int root_x = src[finalCandidates[bestIdx].startIdx].x;\n    int root_y = src[finalCandidates[bestIdx].startIdx].y;\n\n    output_tree(root_x, root_y);\n    for (auto &cmd : bestRes.ops) {\n        cout << cmd << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic constexpr int COORD_MAX = 100000;\nstatic constexpr int ENC_SHIFT = 17;\nstatic constexpr int ENC_MASK = (1 << ENC_SHIFT) - 1;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct GridData {\n    int G, sx, sy;\n    int W, H;\n    vector<int> xs, ys;\n    vector<int> w;\n};\n\nstruct Component {\n    vector<int> cells;\n    int prize = 0;\n};\n\nstruct ComponentsResult {\n    vector<Component> comps;\n    vector<int> compId;\n    int bestCid = -1;\n    int positiveCount = 0;\n};\n\nstruct Candidate {\n    vector<Pt> poly;\n    long long approx = 0;\n    int perim = 0;\n    int minx = 0, maxx = 0, miny = 0, maxy = 0;\n    uint64_t hash = 0;\n};\n\nstruct FishEnv {\n    vector<Pt> pts;\n    vector<int> sgn;\n    vector<int> ordY;\n    vector<vector<int>> byX, byY;\n};\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick() : n(0) {}\n    Fenwick(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add_coord(int coord, int val) {\n        for (int i = coord + 1; i <= n; i += i & -i) bit[i] += val;\n    }\n    int sum_exclusive(int x) const { // coords < x\n        int s = 0;\n        for (int i = x; i > 0; i -= i & -i) s += bit[i];\n        return s;\n    }\n};\n\nstatic inline long long enc_xy(int x, int y) {\n    return (static_cast<long long>(x) << ENC_SHIFT) | y;\n}\n\nstatic inline Pt dec_xy(long long v) {\n    return Pt{static_cast<int>(v >> ENC_SHIFT), static_cast<int>(v & ENC_MASK)};\n}\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nvector<int> create_bounds(int G, int shift) {\n    vector<int> res;\n    res.push_back(0);\n    int cur = 0;\n    if (shift > 0) {\n        res.push_back(shift);\n        cur = shift;\n    }\n    while (cur < COORD_MAX) {\n        cur = min(COORD_MAX, cur + G);\n        if (cur > res.back()) res.push_back(cur);\n    }\n    return res;\n}\n\nint coord_to_index(int v, int G, int shift, int cells) {\n    if (v == COORD_MAX) return cells - 1;\n    if (shift > 0 && v < shift) return 0;\n    int idx;\n    if (shift == 0) idx = v / G;\n    else idx = 1 + (v - shift) / G;\n    if (idx < 0) idx = 0;\n    if (idx >= cells) idx = cells - 1;\n    return idx;\n}\n\nGridData build_grid(const vector<Pt>& macks, const vector<Pt>& sards, int G, int sx, int sy) {\n    GridData gd;\n    gd.G = G; gd.sx = sx; gd.sy = sy;\n    gd.xs = create_bounds(G, sx);\n    gd.ys = create_bounds(G, sy);\n    gd.W = (int)gd.xs.size() - 1;\n    gd.H = (int)gd.ys.size() - 1;\n    gd.w.assign(gd.W * gd.H, 0);\n\n    auto id = [&](int x, int y) { return y * gd.W + x; };\n\n    for (const auto& p : macks) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]++;\n    }\n    for (const auto& p : sards) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]--;\n    }\n    return gd;\n}\n\nlong long region_sum(const vector<char>& occ, const vector<int>& w) {\n    long long s = 0;\n    for (int i = 0; i < (int)occ.size(); i++) if (occ[i]) s += w[i];\n    return s;\n}\n\nvector<char> best_rectangle_region(const GridData& gd) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    long long best = LLONG_MIN;\n    int bestL = -1, bestR = -1, bestB = -1, bestT = -1;\n\n    vector<long long> tmp(H);\n    for (int L = 0; L < W; L++) {\n        fill(tmp.begin(), tmp.end(), 0);\n        for (int R = L; R < W; R++) {\n            for (int y = 0; y < H; y++) tmp[y] += gd.w[id(R, y)];\n            long long cur = 0;\n            int st = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = tmp[y];\n                    st = y;\n                } else {\n                    cur += tmp[y];\n                }\n                if (cur > best) {\n                    best = cur;\n                    bestL = L; bestR = R; bestB = st; bestT = y;\n                }\n            }\n        }\n    }\n\n    vector<char> occ(W * H, 0);\n    if (best <= 0 || bestL < 0) return occ;\n    for (int y = bestB; y <= bestT; y++) {\n        for (int x = bestL; x <= bestR; x++) occ[id(x, y)] = 1;\n    }\n    return occ;\n}\n\nvector<char> graph_cut_select(const GridData& gd, int lambda) {\n    int W = gd.W, H = gd.H;\n    int V = W * H;\n    int S = V, T = V + 1;\n    mf_graph<long long> mf(V + 2);\n\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int ww = gd.w[v];\n            if (ww >= 0) mf.add_edge(S, v, ww);\n            else mf.add_edge(v, T, -ww);\n\n            int border = 0;\n            if (x == 0) border++;\n            if (x == W - 1) border++;\n            if (y == 0) border++;\n            if (y == H - 1) border++;\n            if (border) mf.add_edge(v, T, 1LL * lambda * border);\n\n            if (x + 1 < W) {\n                int u = id(x + 1, y);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n            if (y + 1 < H) {\n                int u = id(x, y + 1);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n        }\n    }\n\n    mf.flow(S, T);\n    auto cut = mf.min_cut(S);\n    vector<char> sel(V, 0);\n    for (int i = 0; i < V; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nComponentsResult get_components(const vector<char>& sel, const vector<int>& w, int W, int H) {\n    ComponentsResult res;\n    int V = W * H;\n    res.compId.assign(V, -1);\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    int cid = 0;\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int s = id(x, y);\n            if (!sel[s] || res.compId[s] != -1) continue;\n\n            queue<int> q;\n            q.push(s);\n            res.compId[s] = cid;\n            Component comp;\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                comp.cells.push_back(v);\n                comp.prize += w[v];\n\n                int vx = v % W, vy = v / W;\n                static const int dx[4] = {1, -1, 0, 0};\n                static const int dy[4] = {0, 0, 1, -1};\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = vx + dx[dir], ny = vy + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (!sel[u] || res.compId[u] != -1) continue;\n                    res.compId[u] = cid;\n                    q.push(u);\n                }\n            }\n\n            res.comps.push_back(std::move(comp));\n            cid++;\n        }\n    }\n\n    int bestPrize = INT_MIN;\n    for (int i = 0; i < (int)res.comps.size(); i++) {\n        if (res.comps[i].prize > 0) {\n            res.positiveCount++;\n            if (res.comps[i].prize > bestPrize) {\n                bestPrize = res.comps[i].prize;\n                res.bestCid = i;\n            }\n        }\n    }\n    return res;\n}\n\nvoid fill_holes(vector<char>& occ, int W, int H) {\n    int PW = W + 2, PH = H + 2;\n    vector<char> vis(PW * PH, 0);\n\n    auto pid = [&](int x, int y) { return y * PW + x; };\n    auto blocked = [&](int x, int y) -> bool {\n        if (x == 0 || x == W + 1 || y == 0 || y == H + 1) return false;\n        return occ[(y - 1) * W + (x - 1)];\n    };\n\n    queue<int> q;\n    q.push(pid(0, 0));\n    vis[pid(0, 0)] = 1;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % PW, y = v / PW;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (nx < 0 || nx >= PW || ny < 0 || ny >= PH) continue;\n            int u = pid(nx, ny);\n            if (vis[u] || blocked(nx, ny)) continue;\n            vis[u] = 1;\n            q.push(u);\n        }\n    }\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = y * W + x;\n            if (!occ[v] && !vis[pid(x + 1, y + 1)]) occ[v] = 1;\n        }\n    }\n}\n\nint count_occ_neighbors(const vector<char>& occ, int v, int W, int H) {\n    int x = v % W, y = v / W;\n    int k = 0;\n    if (x > 0 && occ[v - 1]) k++;\n    if (x + 1 < W && occ[v + 1]) k++;\n    if (y > 0 && occ[v - W]) k++;\n    if (y + 1 < H && occ[v + W]) k++;\n    return k;\n}\n\nbool is_boundary_cell(const vector<char>& occ, int v, int W, int H) {\n    if (!occ[v]) return false;\n    int x = v % W, y = v / W;\n    if (x == 0 || x == W - 1 || y == 0 || y == H - 1) return true;\n    if (!occ[v - 1] || !occ[v + 1] || !occ[v - W] || !occ[v + W]) return true;\n    return false;\n}\n\nbool can_remove_connected(const vector<char>& occ, int rem, int W, int H, int occCount) {\n    if (occCount <= 1) return false;\n    int k = count_occ_neighbors(occ, rem, W, H);\n    if (k <= 1) return true;\n\n    int start = -1;\n    for (int i = 0; i < (int)occ.size(); i++) {\n        if (i != rem && occ[i]) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return false;\n\n    vector<char> vis(occ.size(), 0);\n    queue<int> q;\n    q.push(start);\n    vis[start] = 1;\n    int seen = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (!inside(nx, ny)) continue;\n            int u = id(nx, ny);\n            if (u == rem || !occ[u] || vis[u]) continue;\n            vis[u] = 1;\n            seen++;\n            q.push(u);\n        }\n    }\n    return seen == occCount - 1;\n}\n\nvoid local_hill_climb(vector<char>& occ, const vector<int>& w, int W, int H, int beta) {\n    auto id = [&](int x, int y) { return y * W + x; };\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n\n    int occCount = 0;\n    for (char c : occ) if (c) occCount++;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    for (int pass = 0; pass < 3; pass++) {\n        bool changed = false;\n\n        {\n            vector<pair<int,int>> cand;\n            for (int v = 0; v < W * H; v++) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                bool adj = false;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) {\n                        adj = true;\n                        k++;\n                    }\n                }\n                if (!adj) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 60) cand.resize(60);\n\n            for (auto [ng, v] : cand) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) k++;\n                }\n                if (k == 0) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) {\n                    occ[v] = 1;\n                    occCount++;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        {\n            vector<pair<int,int>> cand;\n            for (int v = 0; v < W * H; v++) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 60) cand.resize(60);\n\n            for (auto [ng, v] : cand) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain <= 0) continue;\n                if (can_remove_connected(occ, v, W, H, occCount)) {\n                    occ[v] = 0;\n                    occCount--;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid refine_occ(vector<char>& occ, const vector<int>& w, int W, int H) {\n    fill_holes(occ, W, H);\n    local_hill_climb(occ, w, W, H, 1);\n    local_hill_climb(occ, w, W, H, 2);\n    fill_holes(occ, W, H);\n}\n\nvector<int> top_positive_components(const ComponentsResult& cr, int K) {\n    vector<int> ids;\n    for (int i = 0; i < (int)cr.comps.size(); i++) {\n        if (cr.comps[i].prize > 0) ids.push_back(i);\n    }\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (cr.comps[a].prize != cr.comps[b].prize) return cr.comps[a].prize > cr.comps[b].prize;\n        return cr.comps[a].cells.size() < cr.comps[b].cells.size();\n    });\n    if ((int)ids.size() > K) ids.resize(K);\n    return ids;\n}\n\nvector<char> greedy_connect_mode(\n    const vector<char>& sel,\n    const ComponentsResult& cr,\n    const vector<int>& w,\n    int W, int H,\n    int seedCid,\n    int mode\n) {\n    int V = W * H;\n    vector<char> occ(V, 0);\n    if (seedCid < 0 || seedCid >= (int)cr.comps.size()) return occ;\n    if (cr.comps[seedCid].prize <= 0) return occ;\n\n    int C = (int)cr.comps.size();\n    vector<char> goodComp(C, 0);\n    for (int i = 0; i < C; i++) goodComp[i] = (cr.comps[i].prize > 0);\n\n    vector<char> added(C, 0);\n    for (int v : cr.comps[seedCid].cells) occ[v] = 1;\n    added[seedCid] = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    auto is_good_sel = [&](int v) -> bool {\n        if (!sel[v]) return false;\n        int cid = cr.compId[v];\n        return cid >= 0 && goodComp[cid];\n    };\n\n    int gainMul = (mode == 0 ? 8 : 12);\n\n    auto enter_cost = [&](int v) -> int {\n        if (occ[v]) return 0;\n        if (is_good_sel(v)) return 0;\n        int ww = w[v];\n        if (mode == 0) {\n            if (ww >= 2) return 0;\n            if (ww == 1) return 1;\n            if (ww == 0) return 4;\n            return 4 + 6 * (-ww);\n        } else {\n            if (ww >= 1) return 0;\n            if (ww == 0) return 2;\n            return 2 + 4 * (-ww);\n        }\n    };\n\n    for (int iter = 0; iter < 12; iter++) {\n        const int INF = 1e9;\n        vector<int> dist(V, INF), parent(V, -1);\n        priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n\n        for (int v = 0; v < V; v++) {\n            if (occ[v]) {\n                dist[v] = 0;\n                pq.push({0, v});\n            }\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            int x = v % W, y = v / W;\n            static const int dx[4] = {1, -1, 0, 0};\n            static const int dy[4] = {0, 0, 1, -1};\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!inside(nx, ny)) continue;\n                int u = id(nx, ny);\n                int nd = d + enter_cost(u);\n                if (nd < dist[u]) {\n                    dist[u] = nd;\n                    parent[u] = v;\n                    pq.push({nd, u});\n                }\n            }\n        }\n\n        long long bestGain = 0;\n        int chooseCid = -1;\n        int chooseCell = -1;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!goodComp[cid] || added[cid]) continue;\n            int bestDist = INF;\n            int bestCell = -1;\n            for (int v : cr.comps[cid].cells) {\n                if (dist[v] < bestDist) {\n                    bestDist = dist[v];\n                    bestCell = v;\n                }\n            }\n            if (bestCell == -1) continue;\n            long long gain = 1LL * gainMul * cr.comps[cid].prize - bestDist;\n            if (gain > bestGain) {\n                bestGain = gain;\n                chooseCid = cid;\n                chooseCell = bestCell;\n            }\n        }\n\n        if (chooseCid == -1) break;\n\n        vector<char> touched(C, 0);\n        int v = chooseCell;\n        while (v != -1 && !occ[v]) {\n            occ[v] = 1;\n            if (is_good_sel(v)) touched[cr.compId[v]] = 1;\n            v = parent[v];\n        }\n        touched[chooseCid] = 1;\n\n        bool anyNew = false;\n        for (int cid = 0; cid < C; cid++) {\n            if (!touched[cid] || added[cid]) continue;\n            added[cid] = 1;\n            anyNew = true;\n            for (int u : cr.comps[cid].cells) occ[u] = 1;\n        }\n        if (!anyNew) break;\n    }\n\n    return occ;\n}\n\nvector<Pt> build_polygon(const GridData& gd, const vector<char>& occ) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    unordered_map<long long, long long> nxt;\n    nxt.reserve((size_t)occ.size() * 3 + 16);\n    bool bad = false;\n    long long start = -1;\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) {\n        long long a = enc_xy(x1, y1);\n        long long b = enc_xy(x2, y2);\n        auto it = nxt.find(a);\n        if (it != nxt.end() && it->second != b) bad = true;\n        nxt[a] = b;\n        if (start == -1 || a < start) start = a;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            if (!occ[v]) continue;\n            int x0 = gd.xs[x], x1 = gd.xs[x + 1];\n            int y0 = gd.ys[y], y1 = gd.ys[y + 1];\n\n            if (y == 0 || !occ[id(x, y - 1)]) add_edge(x0, y0, x1, y0);\n            if (x == W - 1 || !occ[id(x + 1, y)]) add_edge(x1, y0, x1, y1);\n            if (y == H - 1 || !occ[id(x, y + 1)]) add_edge(x1, y1, x0, y1);\n            if (x == 0 || !occ[id(x - 1, y)]) add_edge(x0, y1, x0, y0);\n        }\n    }\n\n    if (bad || start == -1) return {};\n\n    vector<Pt> poly;\n    long long cur = start;\n    int steps = 0;\n\n    while (true) {\n        poly.push_back(dec_xy(cur));\n        auto it = nxt.find(cur);\n        if (it == nxt.end()) return {};\n        cur = it->second;\n        steps++;\n        if (cur == start) break;\n        if (steps > (int)nxt.size() + 5) return {};\n    }\n\n    if (steps != (int)nxt.size()) return {};\n\n    auto collinear = [&](const Pt& a, const Pt& b, const Pt& c) {\n        return (a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y);\n    };\n\n    bool changed = true;\n    while (changed && (int)poly.size() > 4) {\n        changed = false;\n        vector<Pt> np;\n        int m = (int)poly.size();\n        np.reserve(m);\n        for (int i = 0; i < m; i++) {\n            const Pt& prev = poly[(i - 1 + m) % m];\n            const Pt& curp = poly[i];\n            const Pt& nextp = poly[(i + 1) % m];\n            if (collinear(prev, curp, nextp)) changed = true;\n            else np.push_back(curp);\n        }\n        poly.swap(np);\n    }\n\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return {};\n\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        long long e = enc_xy(poly[i].x, poly[i].y);\n        if (!seen.insert(e).second) return {};\n        perim += manhattan(poly[i], poly[(i + 1) % poly.size()]);\n    }\n    if (perim > 400000) return {};\n\n    return poly;\n}\n\nbool basic_valid_poly(const vector<Pt>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        const auto& a = poly[i];\n        const auto& b = poly[(i + 1) % poly.size()];\n        if (a.x != b.x && a.y != b.y) return false;\n        if (a.x == b.x && a.y == b.y) return false;\n        if (a.x < 0 || a.x > COORD_MAX || a.y < 0 || a.y > COORD_MAX) return false;\n        long long e = enc_xy(a.x, a.y);\n        if (!seen.insert(e).second) return false;\n        perim += manhattan(a, b);\n    }\n    return perim <= 400000;\n}\n\nuint64_t hash_poly(const vector<Pt>& poly) {\n    uint64_t h = 1469598103934665603ULL;\n    for (const auto& p : poly) {\n        uint64_t v = (uint64_t)p.x * 1000003ULL + (uint64_t)p.y + 0x9e3779b97f4a7c15ULL;\n        h ^= v;\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)poly.size() + 0x517cc1b727220a95ULL;\n    return h;\n}\n\nCandidate make_candidate(vector<Pt> poly, long long approx) {\n    Candidate c;\n    c.poly = std::move(poly);\n    c.approx = approx;\n    c.perim = 0;\n    c.minx = c.maxx = c.poly[0].x;\n    c.miny = c.maxy = c.poly[0].y;\n    for (int i = 0; i < (int)c.poly.size(); i++) {\n        c.perim += manhattan(c.poly[i], c.poly[(i + 1) % c.poly.size()]);\n        c.minx = min(c.minx, c.poly[i].x);\n        c.maxx = max(c.maxx, c.poly[i].x);\n        c.miny = min(c.miny, c.poly[i].y);\n        c.maxy = max(c.maxy, c.poly[i].y);\n    }\n    c.hash = hash_poly(c.poly);\n    return c;\n}\n\npair<vector<int>, bool> snap_axis_values(const vector<int>& vals, const vector<char>& has) {\n    vector<int> nv = vals;\n    bool changed = false;\n    int K = (int)vals.size();\n    for (int i = 0; i < K; i++) {\n        int L = (i == 0 ? 0 : nv[i - 1] + 1);\n        int R = (i + 1 < K ? vals[i + 1] - 1 : COORD_MAX);\n        if (L > R) {\n            nv[i] = vals[i];\n            continue;\n        }\n        if (!has[vals[i]]) {\n            nv[i] = vals[i];\n            continue;\n        }\n        int best = vals[i];\n        bool found = false;\n        int lim = max(vals[i] - L, R - vals[i]);\n        for (int d = 1; d <= lim; d++) {\n            int a = vals[i] - d;\n            if (a >= L && !has[a]) {\n                best = a;\n                found = true;\n                break;\n            }\n            int b = vals[i] + d;\n            if (b <= R && !has[b]) {\n                best = b;\n                found = true;\n                break;\n            }\n        }\n        if (found) {\n            nv[i] = best;\n            if (best != vals[i]) changed = true;\n        } else {\n            nv[i] = vals[i];\n        }\n    }\n    return {nv, changed};\n}\n\nvector<Pt> snap_poly_lines(const vector<Pt>& poly, const vector<char>& hasX, const vector<char>& hasY) {\n    vector<int> ux, uy;\n    ux.reserve(poly.size());\n    uy.reserve(poly.size());\n    for (auto& p : poly) {\n        ux.push_back(p.x);\n        uy.push_back(p.y);\n    }\n    sort(ux.begin(), ux.end());\n    ux.erase(unique(ux.begin(), ux.end()), ux.end());\n    sort(uy.begin(), uy.end());\n    uy.erase(unique(uy.begin(), uy.end()), uy.end());\n\n    auto [nx, cx] = snap_axis_values(ux, hasX);\n    auto [ny, cy] = snap_axis_values(uy, hasY);\n    if (!cx && !cy) return {};\n\n    unordered_map<int,int> mx, my;\n    mx.reserve(ux.size() * 2 + 1);\n    my.reserve(uy.size() * 2 + 1);\n    for (int i = 0; i < (int)ux.size(); i++) mx[ux[i]] = nx[i];\n    for (int i = 0; i < (int)uy.size(); i++) my[uy[i]] = ny[i];\n\n    vector<Pt> out = poly;\n    for (auto& p : out) {\n        p.x = mx[p.x];\n        p.y = my[p.y];\n    }\n    if (!basic_valid_poly(out)) return {};\n    return out;\n}\n\nbool push_candidate(\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    vector<Pt> poly,\n    long long approx\n) {\n    if (poly.empty()) return false;\n    Candidate c = make_candidate(std::move(poly), approx);\n    if (!seenHash.insert(c.hash).second) return false;\n    cands.push_back(std::move(c));\n    return true;\n}\n\nvoid try_add_candidate(\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const GridData& gd,\n    const vector<char>& occ,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    long long approx = region_sum(occ, gd.w);\n    if (approx < 0) return;\n\n    auto poly = build_polygon(gd, occ);\n    if (poly.empty()) return;\n\n    // Important: snap the polygon we just built, not cands.back().\n    auto snapped = snap_poly_lines(poly, hasX, hasY);\n\n    push_candidate(cands, seenHash, std::move(poly), approx);\n    if (!snapped.empty()) push_candidate(cands, seenHash, std::move(snapped), approx);\n}\n\nint exact_score_fast(const Candidate& c, const FishEnv& env) {\n    int P = (int)env.pts.size();\n    vector<char> on(P, 0);\n\n    vector<pair<int,int>> addEv, remEv; // (y, x)\n    addEv.reserve(c.poly.size());\n    remEv.reserve(c.poly.size());\n\n    int m = (int)c.poly.size();\n    for (int i = 0; i < m; i++) {\n        Pt a = c.poly[i];\n        Pt b = c.poly[(i + 1) % m];\n        if (a.x == b.x) {\n            int x = a.x;\n            int y1 = min(a.y, b.y), y2 = max(a.y, b.y);\n\n            for (int idx : env.byX[x]) {\n                int py = env.pts[idx].y;\n                if (y1 <= py && py <= y2) on[idx] = 1;\n            }\n\n            if (y1 < y2) {\n                addEv.push_back({y1, x});\n                remEv.push_back({y2, x});\n            }\n        } else {\n            int y = a.y;\n            int x1 = min(a.x, b.x), x2 = max(a.x, b.x);\n\n            for (int idx : env.byY[y]) {\n                int px = env.pts[idx].x;\n                if (x1 <= px && px <= x2) on[idx] = 1;\n            }\n        }\n    }\n\n    sort(addEv.begin(), addEv.end());\n    sort(remEv.begin(), remEv.end());\n\n    Fenwick fw(COORD_MAX + 1);\n    int ai = 0, ri = 0;\n    int diff = 0;\n\n    for (int idx : env.ordY) {\n        const Pt& p = env.pts[idx];\n        if (p.y < c.miny) continue;\n        if (p.y > c.maxy) break;\n\n        while (ri < (int)remEv.size() && remEv[ri].first <= p.y) {\n            fw.add_coord(remEv[ri].second, -1);\n            ri++;\n        }\n        while (ai < (int)addEv.size() && addEv[ai].first <= p.y) {\n            fw.add_coord(addEv[ai].second, +1);\n            ai++;\n        }\n\n        if (p.x < c.minx || p.x > c.maxx) continue;\n\n        bool inside;\n        if (on[idx]) inside = true;\n        else inside = (fw.sum_exclusive(p.x) & 1);\n\n        if (inside) diff += env.sgn[idx];\n    }\n\n    return max(0, diff + 1);\n}\n\nvector<Pt> find_empty_square(const unordered_set<long long>& pts) {\n    auto has = [&](int x, int y) -> bool {\n        return pts.find(1LL * x * (COORD_MAX + 1) + y) != pts.end();\n    };\n    for (int x = 0; x <= 1000; x++) {\n        for (int y = 0; y <= 1000; y++) {\n            if (x + 1 > COORD_MAX || y + 1 > COORD_MAX) continue;\n            if (!has(x, y) && !has(x + 1, y) && !has(x, y + 1) && !has(x + 1, y + 1)) {\n                return {{x, y}, {x + 1, y}, {x + 1, y + 1}, {x, y + 1}};\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nvoid process_selection(\n    const GridData& gd,\n    const vector<char>& sel,\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    auto cr = get_components(sel, gd.w, gd.W, gd.H);\n    auto top = top_positive_components(cr, 3);\n    if (top.empty()) return;\n\n    // Best few single components\n    for (int cid : top) {\n        vector<char> occ(gd.W * gd.H, 0);\n        for (int v : cr.comps[cid].cells) occ[v] = 1;\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n\n    // Conservative corridor-connection from top 2 seeds\n    int seeds = min(2, (int)top.size());\n    for (int i = 0; i < seeds; i++) {\n        int cid = top[i];\n        auto occ = greedy_connect_mode(sel, cr, gd.w, gd.W, gd.H, cid, 0);\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n\n    // More aggressive connection from the best seed only\n    {\n        int cid = top[0];\n        auto occ = greedy_connect_mode(sel, cr, gd.w, gd.W, gd.H, cid, 1);\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, std::milli>(chrono::steady_clock::now() - t0).count();\n    };\n\n    int N;\n    cin >> N;\n\n    vector<Pt> macks(N), sards(N);\n    unordered_set<long long> allPts;\n    allPts.reserve((size_t)2 * N * 2);\n\n    vector<char> hasX(COORD_MAX + 1, 0), hasY(COORD_MAX + 1, 0);\n\n    for (int i = 0; i < N; i++) {\n        cin >> macks[i].x >> macks[i].y;\n        allPts.insert(1LL * macks[i].x * (COORD_MAX + 1) + macks[i].y);\n        hasX[macks[i].x] = 1;\n        hasY[macks[i].y] = 1;\n    }\n    for (int i = 0; i < N; i++) {\n        cin >> sards[i].x >> sards[i].y;\n        allPts.insert(1LL * sards[i].x * (COORD_MAX + 1) + sards[i].y);\n        hasX[sards[i].x] = 1;\n        hasY[sards[i].y] = 1;\n    }\n\n    FishEnv env;\n    env.pts.reserve(2 * N);\n    env.sgn.reserve(2 * N);\n    env.byX.assign(COORD_MAX + 1, {});\n    env.byY.assign(COORD_MAX + 1, {});\n    for (int i = 0; i < N; i++) {\n        int idx = (int)env.pts.size();\n        env.pts.push_back(macks[i]);\n        env.sgn.push_back(+1);\n        env.byX[macks[i].x].push_back(idx);\n        env.byY[macks[i].y].push_back(idx);\n    }\n    for (int i = 0; i < N; i++) {\n        int idx = (int)env.pts.size();\n        env.pts.push_back(sards[i]);\n        env.sgn.push_back(-1);\n        env.byX[sards[i].x].push_back(idx);\n        env.byY[sards[i].y].push_back(idx);\n    }\n    env.ordY.resize(env.pts.size());\n    iota(env.ordY.begin(), env.ordY.end(), 0);\n    sort(env.ordY.begin(), env.ordY.end(), [&](int a, int b) {\n        if (env.pts[a].y != env.pts[b].y) return env.pts[a].y < env.pts[b].y;\n        return env.pts[a].x < env.pts[b].x;\n    });\n\n    vector<Candidate> cands;\n    cands.reserve(1600);\n    unordered_set<uint64_t> seenHash;\n    seenHash.reserve(8192);\n\n    vector<int> Gs = {1000, 1400, 1800, 2300, 3000};\n\n    bool stopGen = false;\n    for (int G : Gs) {\n        vector<pair<int,int>> shifts = {\n            {0, 0},\n            {0, G / 2},\n            {G / 2, 0},\n            {G / 2, G / 2}\n        };\n\n        vector<int> lambdas;\n        if (G == 1000) lambdas = {1};\n        else if (G <= 1800) lambdas = {1, 2};\n        else lambdas = {1, 2, 3};\n\n        for (auto [sx, sy] : shifts) {\n            if (elapsed_ms() > 1700.0) { stopGen = true; break; }\n\n            GridData gd = build_grid(macks, sards, G, sx, sy);\n\n            {\n                auto occ = best_rectangle_region(gd);\n                try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n            }\n\n            // positive cells\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                for (int i = 0; i < gd.W * gd.H; i++) if (gd.w[i] > 0) sel[i] = 1;\n                process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            // denser positive core\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 2) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            // very dense core on fine grids\n            if (G <= 1400) {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 3) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            // nonnegative region on coarse grids\n            if (G >= 2300) {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool anyPos = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 0) sel[i] = 1;\n                    if (gd.w[i] > 0) anyPos = true;\n                }\n                if (anyPos) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            for (int lambda : lambdas) {\n                if (elapsed_ms() > 1770.0) { stopGen = true; break; }\n                auto sel = graph_cut_select(gd, lambda);\n                process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n            if (stopGen) break;\n        }\n        if (stopGen) break;\n    }\n\n    Candidate best = make_candidate(find_empty_square(allPts), 0);\n    int bestScore = exact_score_fast(best, env);\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.perim != b.perim) return a.perim < b.perim;\n        return a.poly.size() < b.poly.size();\n    });\n\n    for (const auto& c : cands) {\n        if (elapsed_ms() > 1985.0) break;\n        int sc = exact_score_fast(c, env);\n        if (sc > bestScore) {\n            bestScore = sc;\n            best = c;\n        }\n    }\n\n    cout << best.poly.size() << '\\n';\n    for (auto& p : best.poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Dim {\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 baseScore = 1e100;\n    double robustScore = 1e100;\n    uint64_t hash = 0;\n};\n\nstruct ShelfSol {\n    char dir = 'L'; // 'L' = row shelf, 'U' = column shelf\n    vector<unsigned char> used, rot, brk; // if used[i], brk[i]=1 means starts new group among used items\n    double score = 1e100;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstatic uint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    h ^= splitmix64((uint64_t)ops.size());\n    for (const auto& op : ops) {\n        uint64_t v = 0;\n        v ^= (uint64_t)(op.p + 1) * 1000003ULL;\n        v ^= (uint64_t)(op.r + 7) * 10007ULL;\n        v ^= (uint64_t)(unsigned char)(op.d) * 911382323ULL;\n        v ^= (uint64_t)(op.b + 2) * 972663749ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\nstatic bool overlap1D(double l1, double r1, double l2, double r2) {\n    const double EPS = 1e-9;\n    return max(l1, l2) + EPS < min(r1, r2);\n}\n\nstatic double exact_score(const vector<Dim>& dims, const vector<Op>& ops) {\n    int N = (int)dims.size();\n    vector<double> x1(N, 0), y1(N, 0), x2(N, 0), y2(N, 0);\n    vector<char> placed(N, 0), used(N, 0);\n\n    double W = 0, H = 0;\n\n    for (const auto& op : ops) {\n        int p = op.p;\n        double w = op.r ? dims[p].h : dims[p].w;\n        double h = op.r ? dims[p].w : dims[p].h;\n\n        double x = 0, y = 0;\n\n        if (op.d == 'U') {\n            x = (op.b == -1 ? 0.0 : x2[op.b]);\n            y = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(x, x + w, x1[j], x2[j])) {\n                    y = max(y, y2[j]);\n                }\n            }\n        } else {\n            y = (op.b == -1 ? 0.0 : y2[op.b]);\n            x = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(y, y + h, y1[j], y2[j])) {\n                    x = max(x, x2[j]);\n                }\n            }\n        }\n\n        x1[p] = x; y1[p] = y;\n        x2[p] = x + w; y2[p] = y + h;\n        placed[p] = used[p] = 1;\n\n        W = max(W, x2[p]);\n        H = max(H, y2[p]);\n    }\n\n    double penalty = 0.0;\n    for (int i = 0; i < N; i++) {\n        if (!used[i]) penalty += dims[i].w + dims[i].h;\n    }\n    return W + H + penalty;\n}\n\nstatic pair<long long, long long> query_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n\n    long long W, H;\n    if (!(cin >> W >> H)) exit(0);\n    if (W < 0 || H < 0) exit(0);\n    return {W, H};\n}\n\nstatic vector<Op> make_line_ops(const vector<int>& ids, char dir, int rot = 0) {\n    vector<Op> ops;\n    ops.reserve(ids.size());\n    for (int x : ids) ops.push_back({x, rot, dir, -1});\n    return ops;\n}\n\nstatic vector<Op> make_all_line_ops(int N, char dir, int rot = 0) {\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    return make_line_ops(ids, dir, rot);\n}\n\nstatic vector<int> top_k_indices(const vector<double>& vals, int K) {\n    int N = (int)vals.size();\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    nth_element(ids.begin(), ids.begin() + K, ids.end(), [&](int a, int b) {\n        return vals[a] > vals[b];\n    });\n    ids.resize(K);\n    sort(ids.begin(), ids.end());\n    return ids;\n}\n\nstatic vector<double> correct_groupwise(\n    const vector<double>& y,\n    double totalM, double tauTotal,\n    const vector<int>* subset,\n    double subsetM, double tauSubset\n) {\n    int N = (int)y.size();\n    vector<double> x(N);\n    double Sy = 0.0;\n    for (double v : y) Sy += v;\n\n    if (subset == nullptr || subset->empty() || (int)subset->size() == N) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    vector<char> inS(N, 0);\n    double SS = 0.0;\n    for (int idx : *subset) {\n        inS[idx] = 1;\n        SS += y[idx];\n    }\n    double nS = (double)subset->size();\n\n    double d0 = Sy - totalM;\n    double d1 = SS - subsetM;\n\n    double a11 = N + tauTotal;\n    double a12 = nS;\n    double a21 = nS;\n    double a22 = nS + tauSubset;\n    double det = a11 * a22 - a12 * a21;\n    if (fabs(det) < 1e-12) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    double A = (d0 * a22 - d1 * a12) / det;\n    double B = (a11 * d1 - a21 * d0) / det;\n\n    for (int i = 0; i < N; i++) {\n        double v = y[i] - A - (inS[i] ? B : 0.0);\n        x[i] = max(1.0, v);\n    }\n    return x;\n}\n\nstatic inline void get_ab(const Dim& d, char dir, int rot, double& a, double& b) {\n    if (dir == 'L') {\n        // row shelf: a = width, b = height\n        a = rot ? d.h : d.w;\n        b = rot ? d.w : d.h;\n    } else {\n        // column shelf: a = height, b = width\n        a = rot ? d.w : d.h;\n        b = rot ? d.h : d.w;\n    }\n}\n\nstatic inline double metric_b(const Dim& d, char dir, int rot) {\n    if (dir == 'L') return rot ? d.w : d.h;\n    else return rot ? d.h : d.w;\n}\n\nstatic void normalize_shelf(ShelfSol& s) {\n    int N = (int)s.used.size();\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) s.brk[i] = 0;\n    }\n    int first = -1;\n    for (int i = 0; i < N; i++) if (s.used[i]) {\n        first = i;\n        break;\n    }\n    if (first != -1) s.brk[first] = 1;\n}\n\nstatic double shelf_score_fast(const vector<Dim>& dims, const ShelfSol& s) {\n    int N = (int)dims.size();\n    double pen = 0.0;\n    double maxA = 0.0, sumB = 0.0;\n    double curA = 0.0, curB = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) {\n            pen += dims[i].w + dims[i].h;\n            continue;\n        }\n        double a, b;\n        get_ab(dims[i], s.dir, s.rot[i], a, b);\n\n        if (!active || s.brk[i]) {\n            if (active) {\n                maxA = max(maxA, curA);\n                sumB += curB;\n            }\n            curA = a;\n            curB = b;\n            active = true;\n        } else {\n            curA += a;\n            curB = max(curB, b);\n        }\n    }\n    if (active) {\n        maxA = max(maxA, curA);\n        sumB += curB;\n    }\n    return pen + maxA + sumB;\n}\n\nstatic Candidate shelf_to_candidate(const vector<Dim>& base, const ShelfSol& s) {\n    int N = (int)base.size();\n    vector<vector<pair<int,int>>> groups;\n    bool active = false;\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) continue;\n        if (!active || s.brk[i]) {\n            groups.emplace_back();\n            active = true;\n        }\n        groups.back().push_back({i, (int)s.rot[i]});\n    }\n\n    vector<int> reps;\n    reps.reserve(groups.size());\n    for (auto& g : groups) {\n        int bestIdx = g[0].first;\n        double bestM = metric_b(base[g[0].first], s.dir, g[0].second);\n        for (auto [idx, r] : g) {\n            double m = metric_b(base[idx], s.dir, r);\n            if (m > bestM) {\n                bestM = m;\n                bestIdx = idx;\n            }\n        }\n        reps.push_back(bestIdx);\n    }\n\n    vector<Op> ops;\n    for (int gi = 0; gi < (int)groups.size(); gi++) {\n        int bref = (gi == 0 ? -1 : reps[gi - 1]);\n        for (auto [idx, r] : groups[gi]) {\n            ops.push_back({idx, r, s.dir, bref});\n        }\n    }\n\n    Candidate c;\n    c.ops = move(ops);\n    c.baseScore = exact_score(base, c.ops);\n    c.hash = hash_ops(c.ops);\n    return c;\n}\n\nstatic ShelfSol candidate_to_shelf(const Candidate& c, int N) {\n    ShelfSol s;\n    s.dir = c.ops.empty() ? 'L' : c.ops[0].d;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool first = true;\n    int curb = INT_MIN;\n    for (const auto& op : c.ops) {\n        s.used[op.p] = 1;\n        s.rot[op.p] = (unsigned char)op.r;\n        if (first || op.b != curb) {\n            s.brk[op.p] = 1;\n            curb = op.b;\n            first = false;\n        }\n    }\n    normalize_shelf(s);\n    return s;\n}\n\nstatic double total_area(const vector<Dim>& dims) {\n    long double s = 0;\n    for (auto& d : dims) s += (long double)d.w * d.h;\n    return (double)s;\n}\n\nstatic vector<Dim> sample_posterior(\n    const vector<Dim>& base,\n    double sigma,\n    double alpha,\n    double tauW,\n    double tauH,\n    mt19937_64& rng\n) {\n    int N = (int)base.size();\n    static normal_distribution<double> nd(0.0, 1.0);\n\n    vector<double> uw(N), uh(N);\n    double sumUw = 0.0, sumUh = 0.0;\n    for (int i = 0; i < N; i++) {\n        uw[i] = nd(rng) * alpha * sigma;\n        uh[i] = nd(rng) * alpha * sigma;\n        sumUw += uw[i];\n        sumUh += uh[i];\n    }\n\n    double corrW = -sumUw / (N + tauW);\n    double corrH = -sumUh / (N + tauH);\n\n    vector<Dim> out(N);\n    for (int i = 0; i < N; i++) {\n        out[i].w = max(1.0, base[i].w + uw[i] + corrW);\n        out[i].h = max(1.0, base[i].h + uh[i] + corrH);\n    }\n    return out;\n}\n\nstruct Node {\n    int parent = -1;\n    unsigned char act = 0; // 0=skip, 1=continue/start, 2=new group\n    unsigned char rot = 0;\n    double maxDoneA = 0;\n    double sumDoneB = 0;\n    double curA = 0;\n    double curB = 0;\n    double pen = 0;\n    double eval = 0;\n};\n\nstatic inline double node_exact_score(const Node& s) {\n    return s.pen + max(s.maxDoneA, s.curA) + s.sumDoneB + s.curB;\n}\n\nstatic Candidate beam_shelf(\n    const vector<Dim>& sample,\n    const vector<Dim>& base,\n    char dir,\n    double targetA,\n    int beamWidth,\n    double omitMul\n) {\n    int N = (int)sample.size();\n    vector<double> a0(N), b0(N), a1(N), b1(N), remArea(N + 1);\n\n    for (int i = 0; i < N; i++) {\n        double a, b;\n        get_ab(sample[i], dir, 0, a, b);\n        a0[i] = a; b0[i] = b;\n        get_ab(sample[i], dir, 1, a, b);\n        a1[i] = a; b1[i] = b;\n    }\n\n    remArea[N] = 0.0;\n    for (int i = N - 1; i >= 0; i--) {\n        remArea[i] = remArea[i + 1] + sample[i].w * sample[i].h;\n    }\n\n    auto calc_eval = [&](double maxDoneA, double sumDoneB, double curA, double curB, double pen, int nexti) -> double {\n        double nowA = max(maxDoneA, curA);\n        double assumedA = max(nowA, targetA);\n        if (assumedA < 1.0) assumedA = 1.0;\n        return pen + assumedA + sumDoneB + curB + remArea[nexti] / assumedA;\n    };\n\n    vector<Node> nodes;\n    nodes.reserve(1 + (size_t)N * beamWidth * 5 + 16);\n    nodes.push_back(Node());\n    nodes[0].eval = calc_eval(0, 0, 0, 0, 0, 0);\n\n    vector<int> beam, nxt;\n    beam.push_back(0);\n\n    auto cmp = [&](int x, int y) {\n        if (nodes[x].eval != nodes[y].eval) return nodes[x].eval < nodes[y].eval;\n        return node_exact_score(nodes[x]) < node_exact_score(nodes[y]);\n    };\n\n    for (int i = 0; i < N; i++) {\n        nxt.clear();\n        nxt.reserve((size_t)beam.size() * 5 + 8);\n\n        for (int id : beam) {\n            const Node& s = nodes[id];\n\n            {\n                Node t = s;\n                t.parent = id;\n                t.act = 0;\n                t.rot = 0;\n                t.pen = s.pen + omitMul * (sample[i].w + sample[i].h);\n                t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                nodes.push_back(t);\n                nxt.push_back((int)nodes.size() - 1);\n            }\n\n            for (int r = 0; r < 2; r++) {\n                double a = (r ? a1[i] : a0[i]);\n                double b = (r ? b1[i] : b0[i]);\n\n                if (s.curA == 0.0 && s.curB == 0.0 && s.maxDoneA == 0.0 && s.sumDoneB == 0.0) {\n                    Node t;\n                    t.parent = id;\n                    t.act = 1;\n                    t.rot = (unsigned char)r;\n                    t.maxDoneA = 0.0;\n                    t.sumDoneB = 0.0;\n                    t.curA = a;\n                    t.curB = b;\n                    t.pen = s.pen;\n                    t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                    nodes.push_back(t);\n                    nxt.push_back((int)nodes.size() - 1);\n                } else {\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 1;\n                        t.rot = (unsigned char)r;\n                        t.curA = s.curA + a;\n                        t.curB = max(s.curB, b);\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 2;\n                        t.rot = (unsigned char)r;\n                        t.maxDoneA = max(s.maxDoneA, s.curA);\n                        t.sumDoneB = s.sumDoneB + s.curB;\n                        t.curA = a;\n                        t.curB = b;\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                }\n            }\n        }\n\n        if ((int)nxt.size() > beamWidth) {\n            nth_element(nxt.begin(), nxt.begin() + beamWidth, nxt.end(), cmp);\n            nxt.resize(beamWidth);\n        }\n        sort(nxt.begin(), nxt.end(), cmp);\n        beam.swap(nxt);\n    }\n\n    int bestId = beam[0];\n    double bestExact = node_exact_score(nodes[bestId]);\n    for (int id : beam) {\n        double sc = node_exact_score(nodes[id]);\n        if (sc < bestExact) {\n            bestExact = sc;\n            bestId = id;\n        }\n    }\n\n    vector<int> act(N, 0), rot(N, 0);\n    int cur = bestId;\n    for (int i = N - 1; i >= 0; i--) {\n        act[i] = nodes[cur].act;\n        rot[i] = nodes[cur].rot;\n        cur = nodes[cur].parent;\n    }\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool started = false;\n    for (int i = 0; i < N; i++) {\n        if (act[i] == 0) continue;\n        s.used[i] = 1;\n        s.rot[i] = rot[i];\n        if (!started || act[i] == 2) {\n            s.brk[i] = 1;\n            started = true;\n        }\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    Candidate cand = shelf_to_candidate(base, s);\n    return cand;\n}\n\nstatic ShelfSol random_seed_shelf(const vector<Dim>& base, char dir, double targetA, mt19937_64& rng) {\n    int N = (int)base.size();\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    double curA = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (ur(rng) < 0.03) continue;\n\n        double a0, b0, a1, b1;\n        get_ab(base[i], dir, 0, a0, b0);\n        get_ab(base[i], dir, 1, a1, b1);\n\n        double fit0 = fabs((active ? curA : 0.0) + a0 - targetA) + 0.30 * b0;\n        double fit1 = fabs((active ? curA : 0.0) + a1 - targetA) + 0.30 * b1;\n        int r = (fit1 < fit0 ? 1 : 0);\n\n        double a = (r ? a1 : a0);\n        bool newg = !active || curA + a > targetA * (0.85 + 0.40 * ur(rng));\n\n        s.used[i] = 1;\n        s.rot[i] = r;\n        if (newg) {\n            s.brk[i] = 1;\n            curA = a;\n            active = true;\n        } else {\n            curA += a;\n        }\n    }\n\n    if (!active) {\n        int i = (int)(rng() % N);\n        s.used[i] = 1;\n        s.rot[i] = rng() & 1;\n        s.brk[i] = 1;\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    return s;\n}\n\nstatic void mutate_once(ShelfSol& s, mt19937_64& rng) {\n    int N = (int)s.used.size();\n    int typ = (int)(rng() % 100);\n    int i = (int)(rng() % N);\n\n    if (typ < 40) {\n        if (s.used[i]) {\n            s.rot[i] ^= 1;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else if (typ < 75) {\n        if (s.used[i]) {\n            s.used[i] = 0;\n            s.brk[i] = 0;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else {\n        if (s.used[i]) s.brk[i] ^= 1;\n    }\n}\n\nstatic ShelfSol greedy_polish(const vector<Dim>& base, ShelfSol s) {\n    int N = (int)base.size();\n    normalize_shelf(s);\n    double cur = shelf_score_fast(base, s);\n\n    for (int round = 0; round < 3; round++) {\n        bool improved = false;\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.rot[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_fast(base, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.brk[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_fast(base, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (s.used[i]) {\n                ShelfSol t = s;\n                t.used[i] = 0;\n                t.brk[i] = 0;\n                normalize_shelf(t);\n                double sc = shelf_score_fast(base, t);\n                if (sc + 1e-9 < cur) {\n                    s = move(t);\n                    cur = sc;\n                    improved = true;\n                }\n            } else {\n                double bestSc = cur;\n                ShelfSol bestT = s;\n                for (int r = 0; r < 2; r++) {\n                    for (int b = 0; b < 2; b++) {\n                        ShelfSol t = s;\n                        t.used[i] = 1;\n                        t.rot[i] = (unsigned char)r;\n                        t.brk[i] = (unsigned char)b;\n                        normalize_shelf(t);\n                        double sc = shelf_score_fast(base, t);\n                        if (sc + 1e-9 < bestSc) {\n                            bestSc = sc;\n                            bestT = move(t);\n                        }\n                    }\n                }\n                if (bestSc + 1e-9 < cur) {\n                    s = move(bestT);\n                    cur = bestSc;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    s.score = cur;\n    return s;\n}\n\nstatic ShelfSol local_search(\n    const vector<Dim>& base,\n    ShelfSol seed,\n    mt19937_64& rng,\n    int iterations,\n    chrono::steady_clock::time_point deadline\n) {\n    normalize_shelf(seed);\n    seed.score = shelf_score_fast(base, seed);\n\n    ShelfSol cur = seed, best = seed;\n    double curSc = seed.score, bestSc = seed.score;\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 255) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n\n        ShelfSol nxt = cur;\n        int moves = ((rng() % 5) == 0 ? 2 : 1);\n        for (int k = 0; k < moves; k++) mutate_once(nxt, rng);\n        normalize_shelf(nxt);\n        double sc = shelf_score_fast(base, nxt);\n\n        double prog = (double)it / max(1, iterations - 1);\n        double temp = 25000.0 * pow(0.002, prog) + 1.0;\n\n        if (sc < curSc || ur(rng) < exp((curSc - sc) / temp)) {\n            cur = move(nxt);\n            curSc = sc;\n            if (curSc < bestSc) {\n                best = cur;\n                bestSc = curSc;\n            }\n        }\n    }\n\n    best.score = bestSc;\n    best = greedy_polish(base, best);\n    return best;\n}\n\nstatic double robust_eval_candidate(\n    const Candidate& cand,\n    const vector<vector<Dim>>& worlds\n) {\n    double sum = 0.0, mx = -1e100;\n    for (const auto& w : worlds) {\n        double sc = exact_score(w, cand.ops);\n        sum += sc;\n        mx = max(mx, sc);\n    }\n    double mean = sum / worlds.size();\n    return mean + 0.08 * (mx - mean);\n}\n\nstatic vector<Candidate> generate_candidates(\n    const vector<Dim>& base,\n    int remainingTurns,\n    double sigma,\n    double tauW,\n    double tauH,\n    mt19937_64& rng,\n    chrono::steady_clock::time_point deadline\n) {\n    int N = (int)base.size();\n    double area0 = total_area(base);\n    double rootArea = sqrt(max(1.0, area0));\n\n    int beamDet = (N <= 60 ? 520 : 380);\n    int beamRnd = (N <= 60 ? 220 : 160);\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    auto add_cand = [&](Candidate cand) {\n        if (seen.insert(cand.hash).second) {\n            pool.push_back(move(cand));\n        }\n    };\n\n    vector<double> scales = {0.50, 0.63, 0.78, 0.92, 1.05, 1.20, 1.38, 1.60, 1.88};\n    vector<double> omits = {1.00, 1.12, 1.25, 1.40};\n\n    for (double sc : scales) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        add_cand(beam_shelf(base, base, 'L', rootArea * sc, beamDet, 1.15));\n        add_cand(beam_shelf(base, base, 'U', rootArea * sc, beamDet, 1.15));\n    }\n    for (double om : omits) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        add_cand(beam_shelf(base, base, 'L', rootArea, beamDet, om));\n        add_cand(beam_shelf(base, base, 'U', rootArea, beamDet, om));\n    }\n\n    uniform_real_distribution<double> ul(log(0.45), log(2.20));\n    vector<double> alphas = {0.45, 0.80, 1.20};\n\n    int randomBeamAttempts = min(120, remainingTurns + 50);\n    for (int it = 0; it < randomBeamAttempts; it++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        double alpha = alphas[(size_t)(rng() % alphas.size())];\n        auto sample = sample_posterior(base, sigma, alpha, tauW, tauH, rng);\n        double tgt = sqrt(max(1.0, total_area(sample))) * exp(ul(rng));\n        char dir = ((rng() & 1) ? 'L' : 'U');\n        double om = omits[(size_t)(rng() % omits.size())];\n        add_cand(beam_shelf(sample, base, dir, tgt, beamRnd, om));\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.baseScore < b.baseScore;\n    });\n\n    // Local search on top beam seeds.\n    vector<Candidate> enhanced = pool;\n    int topSeeds = min((int)pool.size(), 16);\n    for (int i = 0; i < topSeeds; i++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        ShelfSol s = candidate_to_shelf(pool[i], N);\n        int iters = (i < 8 ? 7000 : 3500);\n        ShelfSol best = local_search(base, s, rng, iters, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    // Random seeds + local search.\n    for (int t = 0; t < 10; t++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        char dir = (t & 1) ? 'L' : 'U';\n        double sc = exp(ul(rng));\n        ShelfSol s = random_seed_shelf(base, dir, rootArea * sc, rng);\n        ShelfSol best = local_search(base, s, rng, 2500, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    // Robust ranking worlds.\n    vector<vector<Dim>> worlds;\n    worlds.push_back(base);\n    worlds.push_back(sample_posterior(base, sigma, 0.60, tauW, tauH, rng));\n    worlds.push_back(sample_posterior(base, sigma, 1.00, tauW, tauH, rng));\n    worlds.push_back(sample_posterior(base, sigma, 1.40, tauW, tauH, rng));\n\n    for (auto& c : enhanced) {\n        c.robustScore = robust_eval_candidate(c, worlds);\n    }\n\n    sort(enhanced.begin(), enhanced.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.robustScore != b.robustScore) return a.robustScore < b.robustScore;\n        return a.baseScore < b.baseScore;\n    });\n\n    // Keep a manageable pool.\n    if ((int)enhanced.size() > 260) enhanced.resize(260);\n    return enhanced;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    int N, T, sigma_i;\n    cin >> N >> T >> sigma_i;\n    double sigma = sigma_i;\n\n    vector<Dim> obs(N);\n    for (int i = 0; i < N; i++) {\n        cin >> obs[i].w >> obs[i].h;\n    }\n\n    mt19937_64 rng(0x3141592653589793ULL);\n\n    vector<double> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) {\n        obsW[i] = obs[i].w;\n        obsH[i] = obs[i].h;\n    }\n\n    int usedTurns = 0;\n\n    // Calibration plan:\n    // always: total width, total height\n    // if T large enough: focused subset width/height\n    // if T even larger: repeated totals via rotated full-line queries\n    bool useSubset = (T >= 20);\n    bool useRepeatTotals = (T >= 32);\n\n    int K = min(max(6, N / 4), 20);\n    vector<int> subsetW = top_k_indices(obsW, K);\n    vector<int> subsetH = top_k_indices(obsH, K);\n\n    vector<double> totalWidthMeasures, totalHeightMeasures;\n    double subsetWidthMeasure = -1.0, subsetHeightMeasure = -1.0;\n\n    // 1) total width by all-in-row, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 0));\n        (void)Hm;\n        totalWidthMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 2) total height by all-in-column, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 0));\n        (void)Wm;\n        totalHeightMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    // 3) focused width subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetW, 'L', 0));\n        (void)Hm;\n        subsetWidthMeasure = (double)Wm;\n        usedTurns++;\n    }\n\n    // 4) focused height subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetH, 'U', 0));\n        (void)Wm;\n        subsetHeightMeasure = (double)Hm;\n        usedTurns++;\n    }\n\n    // 5) repeat total height via all-in-row, rotated (W = sum h)\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 1));\n        (void)Hm;\n        totalHeightMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 6) repeat total width via all-in-column, rotated (H = sum w)\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 1));\n        (void)Wm;\n        totalWidthMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    int remainingTurns = T - usedTurns;\n\n    auto avg = [](const vector<double>& v) {\n        double s = 0.0;\n        for (double x : v) s += x;\n        return s / v.size();\n    };\n\n    double totalW = avg(totalWidthMeasures);\n    double totalH = avg(totalHeightMeasures);\n    double tauW = 1.0 / (double)totalWidthMeasures.size();\n    double tauH = 1.0 / (double)totalHeightMeasures.size();\n\n    vector<double> corrW = correct_groupwise(\n        obsW, totalW, tauW,\n        (subsetWidthMeasure >= 0 ? &subsetW : nullptr),\n        subsetWidthMeasure, 1.0\n    );\n    vector<double> corrH = correct_groupwise(\n        obsH, totalH, tauH,\n        (subsetHeightMeasure >= 0 ? &subsetH : nullptr),\n        subsetHeightMeasure, 1.0\n    );\n\n    vector<Dim> base(N);\n    for (int i = 0; i < N; i++) {\n        base[i].w = corrW[i];\n        base[i].h = corrH[i];\n    }\n\n    if (remainingTurns <= 0) return 0;\n\n    auto deadline = startTime + chrono::milliseconds(2350);\n    auto pool = generate_candidates(base, remainingTurns, sigma, tauW, tauH, rng, deadline);\n    if (pool.empty()) {\n        Candidate fallback = beam_shelf(base, base, 'L', sqrt(max(1.0, total_area(base))), 200, 1.15);\n        pool.push_back(fallback);\n    }\n\n    vector<int> order;\n    int P = (int)pool.size();\n    vector<char> picked(P, 0);\n\n    int topTake = min(P, max(6, remainingTurns * 2 / 3));\n    for (int i = 0; i < topTake; i++) {\n        picked[i] = 1;\n        order.push_back(i);\n    }\n\n    int rem = remainingTurns - (int)order.size();\n    int cap = min(P, max(remainingTurns, min(P, remainingTurns * 3)));\n    if (rem > 0 && cap > topTake) {\n        for (int s = 0; s < rem; s++) {\n            int idx = topTake + (int)((long long)(2 * s + 1) * (cap - topTake) / (2LL * rem));\n            idx = min(idx, cap - 1);\n            if (!picked[idx]) {\n                picked[idx] = 1;\n                order.push_back(idx);\n            }\n        }\n    }\n\n    for (int i = topTake; i < P && (int)order.size() < remainingTurns; i++) {\n        if (!picked[i]) {\n            picked[i] = 1;\n            order.push_back(i);\n        }\n    }\n    while ((int)order.size() < remainingTurns) {\n        order.push_back(0);\n    }\n\n    for (int turn = 0; turn < remainingTurns; turn++) {\n        auto [Wm, Hm] = query_ops(pool[order[turn]].ops);\n        (void)Wm;\n        (void)Hm;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MAXN = 1000;\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> deg;\n    vector<int> X, Y;\n    vector<bitset<MAXN>> adjMat;\n\n    mt19937_64 rng{chrono::steady_clock::now().time_since_epoch().count()};\n    chrono::steady_clock::time_point start_time, deadline;\n\n    struct State {\n        vector<vector<int>> children;\n        vector<vector<int>> comps;\n        vector<int> roots;\n        vector<int> depth, tin, tout, compId;\n        vector<int> subtreeBeauty;\n        vector<int> maxAbsDepth;\n        long long score = 0;\n    };\n\n    struct Move {\n        long long gain = 0;\n        int par = -1;\n        int child = -1;\n        int parentSub = 0;\n        int parDepth = 0;\n        int parentDeg = 0;\n        int parentA = 0;\n        int childSub = 0;\n    };\n\n    struct DMove {\n        // type: 0 = raise v, 1 = swap (v at d, u at d+1) -> (d+1, d)\n        int type = -1;\n        int v = -1, u = -1;\n        int gain = 0;\n        int newDepth = -1; // depth of moved-up vertex after move\n        int upA = 0, downA = 0;\n    };\n\n    bool time_up() const {\n        return chrono::steady_clock::now() >= deadline;\n    }\n\n    long long remaining_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n            deadline - chrono::steady_clock::now()\n        ).count();\n    }\n\n    static bool betterMove(const Move& a, const Move& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.parDepth != b.parDepth) return a.parDepth > b.parDepth;\n        if (a.parentA != b.parentA) return a.parentA < b.parentA;\n        if (a.parentSub != b.parentSub) return a.parentSub < b.parentSub;\n        if (a.parentDeg != b.parentDeg) return a.parentDeg > b.parentDeg;\n        if (a.childSub != b.childSub) return a.childSub > b.childSub;\n        if (a.child != b.child) return a.child < b.child;\n        return a.par < b.par;\n    }\n\n    static bool betterDMove(const DMove& a, const DMove& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.newDepth != b.newDepth) return a.newDepth > b.newDepth;\n        if (a.type != b.type) return a.type < b.type; // prefer raise over swap on tie\n        if (a.upA != b.upA) return a.upA > b.upA;\n        if (a.downA != b.downA) return a.downA < b.downA;\n        if (a.v != b.v) return a.v < b.v;\n        return a.u < b.u;\n    }\n\n    void rebuild(const vector<int>& parent, State& st) {\n        st.children.assign(N, {});\n        st.roots.clear();\n        st.depth.assign(N, 0);\n        st.tin.assign(N, 0);\n        st.tout.assign(N, 0);\n        st.compId.assign(N, -1);\n        st.subtreeBeauty.assign(N, 0);\n        st.maxAbsDepth.assign(N, 0);\n        st.comps.clear();\n        st.score = 1;\n\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] == -1) st.roots.push_back(v);\n            else st.children[parent[v]].push_back(v);\n        }\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v, int comp) -> void {\n            st.compId[v] = comp;\n            st.tin[v] = timer++;\n            st.comps[comp].push_back(v);\n\n            st.subtreeBeauty[v] = A[v];\n            st.maxAbsDepth[v] = st.depth[v];\n            st.score += 1LL * (st.depth[v] + 1) * A[v];\n\n            for (int ch : st.children[v]) {\n                st.depth[ch] = st.depth[v] + 1;\n                self(self, ch, comp);\n                st.subtreeBeauty[v] += st.subtreeBeauty[ch];\n                st.maxAbsDepth[v] = max(st.maxAbsDepth[v], st.maxAbsDepth[ch]);\n            }\n            st.tout[v] = timer;\n        };\n\n        for (int r : st.roots) {\n            st.depth[r] = 0;\n            st.comps.push_back({});\n            dfs(dfs, r, (int)st.comps.size() - 1);\n        }\n    }\n\n    long long calcScore(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.score;\n    }\n\n    vector<int> depthFromParent(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.depth;\n    }\n\n    vector<int> parentFromDepth(const vector<int>& depth) {\n        vector<int> parent(N, -1);\n        vector<vector<int>> layers(H + 1);\n        for (int v = 0; v < N; ++v) layers[depth[v]].push_back(v);\n\n        for (int d = 1; d <= H; ++d) {\n            for (int v : layers[d]) {\n                int best = -1;\n                for (int to : g[v]) if (depth[to] == d - 1) {\n                    if (best == -1) best = to;\n                    else {\n                        if (A[to] != A[best]) best = (A[to] < A[best] ? to : best);\n                        else if (deg[to] != deg[best]) best = (deg[to] > deg[best] ? to : best);\n                        else if (to < best) best = to;\n                    }\n                }\n                if (best == -1) parent[v] = -1; // should not happen if depth is feasible\n                else parent[v] = best;\n            }\n        }\n        return parent;\n    }\n\n    long long scoreDepth(const vector<int>& depth) {\n        long long sc = 1;\n        for (int v = 0; v < N; ++v) sc += 1LL * (depth[v] + 1) * A[v];\n        return sc;\n    }\n\n    bool makeCandidate(int par, int child, const State& st, Move& mv) {\n        int newDepth = st.depth[par] + 1;\n        if (newDepth > H) return false;\n        if (newDepth <= st.depth[child]) return false;\n\n        if (st.compId[par] == st.compId[child]) {\n            if (st.tin[child] <= st.tin[par] && st.tin[par] < st.tout[child]) {\n                return false;\n            }\n        }\n\n        int delta = newDepth - st.depth[child];\n        if (st.maxAbsDepth[child] + delta > H) return false;\n\n        mv.gain = 1LL * delta * st.subtreeBeauty[child];\n        if (mv.gain <= 0) return false;\n\n        mv.par = par;\n        mv.child = child;\n        mv.parentSub = st.subtreeBeauty[par];\n        mv.parDepth = st.depth[par];\n        mv.parentDeg = deg[par];\n        mv.parentA = A[par];\n        mv.childSub = st.subtreeBeauty[child];\n        return true;\n    }\n\n    bool findMoveDeterministic(const State& st, Move& best) {\n        bool found = false;\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool findMoveRandomized(const State& st, Move& chosen) {\n        vector<Move> cand;\n        cand.reserve(2 * M);\n        long long bestGain = 0;\n\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain * 100 >= bestGain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain * 100 >= bestGain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n        }\n\n        if (bestGain <= 0) return false;\n        sort(cand.begin(), cand.end(), betterMove);\n        int k = min<int>(12, cand.size());\n        uniform_int_distribution<int> dist(0, k - 1);\n        chosen = cand[dist(rng)];\n        return true;\n    }\n\n    void hillClimb(vector<int>& parent, bool randomized) {\n        while (!time_up()) {\n            State st;\n            rebuild(parent, st);\n\n            Move mv;\n            bool ok = randomized ? findMoveRandomized(st, mv)\n                                 : findMoveDeterministic(st, mv);\n            if (!ok) break;\n            parent[mv.child] = mv.par;\n        }\n    }\n\n    bool rerootOptimize(vector<int>& parent) {\n        if (time_up()) return false;\n\n        State st;\n        rebuild(parent, st);\n\n        vector<vector<int>> treeAdj(N);\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] != -1) {\n                treeAdj[v].push_back(parent[v]);\n                treeAdj[parent[v]].push_back(v);\n            }\n        }\n\n        vector<int> newParent = parent;\n        bool changedAny = false;\n\n        auto dfsScore = [&](auto&& self, int v, int p, int d, long long& sc, int& mx,\n                            const vector<vector<int>>& adj) -> void {\n            sc += 1LL * A[v] * d;\n            mx = max(mx, d);\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, d + 1, sc, mx, adj);\n            }\n        };\n\n        auto dfsOrient = [&](auto&& self, int v, int p,\n                             vector<int>& par, const vector<vector<int>>& adj) -> void {\n            par[v] = p;\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, par, adj);\n            }\n        };\n\n        for (const auto& comp : st.comps) {\n            if (time_up()) return changedAny;\n            if (comp.size() <= 1) continue;\n\n            long long bestScore = LLONG_MIN;\n            int bestRoot = comp[0];\n\n            for (int r : comp) {\n                long long sc = 0;\n                int mx = 0;\n                dfsScore(dfsScore, r, -1, 0, sc, mx, treeAdj);\n                if (mx > H) continue;\n\n                bool better = false;\n                if (sc > bestScore) better = true;\n                else if (sc == bestScore) {\n                    if (A[r] < A[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] > deg[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] == deg[bestRoot] && r < bestRoot) better = true;\n                }\n                if (better) {\n                    bestScore = sc;\n                    bestRoot = r;\n                }\n            }\n\n            if (bestScore == LLONG_MIN) continue;\n            dfsOrient(dfsOrient, bestRoot, -1, newParent, treeAdj);\n        }\n\n        if (newParent != parent) {\n            parent.swap(newParent);\n            changedAny = true;\n        }\n        return changedAny;\n    }\n\n    // -------- depth-label local search --------\n\n    bool canRaiseVertex(int v, const vector<int>& depth,\n                        const vector<array<int, 11>>& cnt) {\n        int d = depth[v];\n        if (d >= H) return false;\n        if (cnt[v][d] <= 0) return false; // need some neighbor at depth d\n        for (int x : g[v]) {\n            if (depth[x] == d + 1 && cnt[x][d] == 1) return false;\n        }\n        return true;\n    }\n\n    bool canSwapEdge(int v, int u, const vector<int>& depth,\n                     const vector<array<int, 11>>& cnt) {\n        // require depth[v] = d, depth[u] = d+1\n        int d = depth[v];\n        if (d + 1 != depth[u]) return false;\n        if (A[v] <= A[u]) return false; // improving only\n        if (d >= H) return false;\n\n        // u moves to d, so it must have a neighbor at d-1 (unless d==0)\n        if (d > 0 && cnt[u][d - 1] == 0) return false;\n\n        // vertices at depth d+1 neighboring v must keep a depth-d support\n        for (int x : g[v]) {\n            if (x == u) continue;\n            if (depth[x] == d + 1) {\n                int newCnt = cnt[x][d] - 1 + (adjMat[u][x] ? 1 : 0);\n                if (newCnt <= 0) return false;\n            }\n        }\n\n        // vertices at depth d+2 neighboring u must keep a depth-(d+1) support\n        if (d + 2 <= H) {\n            for (int y : g[u]) {\n                if (depth[y] == d + 2) {\n                    int newCnt = cnt[y][d + 1] - 1 + (adjMat[v][y] ? 1 : 0);\n                    if (newCnt <= 0) return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    void applyRaise(int v, vector<int>& depth, vector<array<int, 11>>& cnt) {\n        int d = depth[v];\n        for (int x : g[v]) {\n            cnt[x][d]--;\n            cnt[x][d + 1]++;\n        }\n        depth[v]++;\n    }\n\n    void applySwap(int v, int u, vector<int>& depth, vector<array<int, 11>>& cnt) {\n        // depth[v] = d, depth[u] = d+1\n        int d = depth[v];\n\n        for (int x : g[v]) {\n            cnt[x][d]--;\n            cnt[x][d + 1]++;\n        }\n        for (int x : g[u]) {\n            cnt[x][d + 1]--;\n            cnt[x][d]++;\n        }\n        depth[v]++;\n        depth[u]--;\n    }\n\n    bool findDepthMove(const vector<int>& depth, const vector<array<int, 11>>& cnt,\n                       bool randomized, DMove& chosen) {\n        DMove best;\n        bool found = false;\n        vector<DMove> cand;\n        cand.reserve(N + M);\n\n        auto pushCand = [&](const DMove& mv) {\n            if (!randomized) {\n                if (!found || betterDMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            } else {\n                if (!found || mv.gain > best.gain) {\n                    best = mv;\n                    cand.clear();\n                    cand.push_back(mv);\n                    found = true;\n                } else if (mv.gain * 100 >= best.gain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n        };\n\n        for (int v = 0; v < N; ++v) {\n            if (canRaiseVertex(v, depth, cnt)) {\n                DMove mv;\n                mv.type = 0;\n                mv.v = v;\n                mv.u = -1;\n                mv.gain = A[v];\n                mv.newDepth = depth[v] + 1;\n                mv.upA = A[v];\n                mv.downA = 0;\n                pushCand(mv);\n            }\n        }\n\n        for (auto [a, b] : edges) {\n            if (depth[a] + 1 == depth[b]) {\n                if (canSwapEdge(a, b, depth, cnt)) {\n                    DMove mv;\n                    mv.type = 1;\n                    mv.v = a;\n                    mv.u = b;\n                    mv.gain = A[a] - A[b];\n                    mv.newDepth = depth[a] + 1;\n                    mv.upA = A[a];\n                    mv.downA = A[b];\n                    pushCand(mv);\n                }\n            } else if (depth[b] + 1 == depth[a]) {\n                if (canSwapEdge(b, a, depth, cnt)) {\n                    DMove mv;\n                    mv.type = 1;\n                    mv.v = b;\n                    mv.u = a;\n                    mv.gain = A[b] - A[a];\n                    mv.newDepth = depth[b] + 1;\n                    mv.upA = A[b];\n                    mv.downA = A[a];\n                    pushCand(mv);\n                }\n            }\n        }\n\n        if (!found) return false;\n\n        if (!randomized) {\n            chosen = best;\n            return true;\n        }\n\n        sort(cand.begin(), cand.end(), betterDMove);\n        int k = min<int>(16, cand.size());\n        uniform_int_distribution<int> dist(0, k - 1);\n        chosen = cand[dist(rng)];\n        return true;\n    }\n\n    void depthLocalSearch(vector<int>& depth, bool randomized) {\n        vector<array<int, 11>> cnt(N);\n        for (int v = 0; v < N; ++v) {\n            for (int d = 0; d <= H; ++d) cnt[v][d] = 0;\n        }\n        for (auto [u, v] : edges) {\n            cnt[u][depth[v]]++;\n            cnt[v][depth[u]]++;\n        }\n\n        int iter = 0;\n        while (!time_up() && iter < 6000) {\n            DMove mv;\n            if (!findDepthMove(depth, cnt, randomized, mv)) break;\n            if (mv.type == 0) applyRaise(mv.v, depth, cnt);\n            else applySwap(mv.v, mv.u, depth, cnt);\n            ++iter;\n        }\n    }\n\n    // -------- initializers --------\n\n    vector<int> buildAllRoots() {\n        return vector<int>(N, -1);\n    }\n\n    vector<int> buildFromKey(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n\n        vector<int> parent(N, -1), depth(N, 0);\n        vector<char> done(N, 0);\n\n        auto betterPar = [&](int x, int y) {\n            if (y == -1) return true;\n            if (depth[x] != depth[y]) return depth[x] > depth[y];\n            if (A[x] != A[y]) return A[x] < A[y];\n            if (deg[x] != deg[y]) return deg[x] > deg[y];\n            return x < y;\n        };\n\n        for (int v : ord) {\n            int bestPar = -1;\n            for (int to : g[v]) {\n                if (!done[to]) continue;\n                if (depth[to] >= H) continue;\n                if (betterPar(to, bestPar)) bestPar = to;\n            }\n            if (bestPar != -1) {\n                parent[v] = bestPar;\n                depth[v] = depth[bestPar] + 1;\n            } else {\n                parent[v] = -1;\n                depth[v] = 0;\n            }\n            done[v] = 1;\n        }\n        return parent;\n    }\n\n    vector<int> bfsDist(int s) {\n        const int INF = 1e9;\n        vector<int> dist(N, INF);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (int to : g[v]) {\n                if (dist[to] != INF) continue;\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n        return dist;\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    vector<int> buildBeautyOrder(double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = 1.0 * A[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildBeautyDegreeOrder(double wA, double wDeg, double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = wA * A[v] - wDeg * deg[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildProjectionOrder(double angle, double wA, double wP, double noiseScale = 1e-4) {\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildSeedDistOrder(int seed, double wD, double wA, double angle = 0.0,\n                                   double wP = 0.0, double noiseScale = 1e-4) {\n        auto dist = bfsDist(seed);\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wD * dist[v] + wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> seedCandidates() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            long long da = 1LL * (X[a] - 500) * (X[a] - 500) + 1LL * (Y[a] - 500) * (Y[a] - 500);\n            long long db = 1LL * (X[b] - 500) * (X[b] - 500) + 1LL * (Y[b] - 500) * (Y[b] - 500);\n            double sa = 18.0 * A[a] - 2.5 * deg[a] + 0.002 * sqrt((double)da);\n            double sb = 18.0 * A[b] - 2.5 * deg[b] + 0.002 * sqrt((double)db);\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n        int K = min(16, N);\n        ord.resize(K);\n        return ord;\n    }\n\n    // -------- candidate pipeline --------\n\n    void tryUpdate(const vector<int>& cand, vector<int>& bestParent, long long& bestScore) {\n        long long sc = calcScore(cand);\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestParent = cand;\n        }\n    }\n\n    void processCandidate(vector<int> parent, bool randomizedFirst,\n                          vector<int>& bestParent, long long& bestScore) {\n        if (time_up()) return;\n\n        // Depth-label improvement\n        {\n            vector<int> depth = depthFromParent(parent);\n            depthLocalSearch(depth, randomizedFirst && remaining_ms() > 900);\n            parent = parentFromDepth(depth);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        // Forest polish\n        if (remaining_ms() > 900) {\n            hillClimb(parent, randomizedFirst);\n            if (!time_up()) rerootOptimize(parent);\n            if (!time_up()) hillClimb(parent, false);\n            tryUpdate(parent, bestParent, bestScore);\n        } else if (remaining_ms() > 400) {\n            hillClimb(parent, false);\n            if (!time_up()) rerootOptimize(parent);\n            tryUpdate(parent, bestParent, bestScore);\n        } else {\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        // Depth-label polish again, now from improved forest\n        {\n            vector<int> depth = depthFromParent(parent);\n            depthLocalSearch(depth, false);\n            parent = parentFromDepth(depth);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        if (remaining_ms() > 250) {\n            hillClimb(parent, false);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n    }\n\n    vector<int> solve() {\n        start_time = chrono::steady_clock::now();\n        deadline = start_time + chrono::milliseconds(1900);\n\n        vector<int> bestParent = buildAllRoots();\n        long long bestScore = calcScore(bestParent);\n\n        auto seeds = seedCandidates();\n\n        // Deterministic / semi-deterministic starts\n        processCandidate(buildAllRoots(), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyOrder(), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyDegreeOrder(1.0, 1.5), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyDegreeOrder(1.6, 2.0), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        const vector<double> fixedAngles = {\n            0.0,\n            acos(-1.0) / 4.0,\n            acos(-1.0) / 2.0,\n            3.0 * acos(-1.0) / 4.0\n        };\n        for (double ang : fixedAngles) {\n            if (time_up()) break;\n            processCandidate(buildProjectionOrder(ang, 1.3, 0.05), true, bestParent, bestScore);\n        }\n\n        for (int i = 0; i < (int)seeds.size() && i < 4 && !time_up(); ++i) {\n            int s = seeds[i];\n            double ang = 2.0 * acos(-1.0) * (i + 1) / 7.0;\n            processCandidate(buildSeedDistOrder(s, 10.0, 1.0, ang, 0.015), true, bestParent, bestScore);\n            if (time_up()) break;\n            processCandidate(buildSeedDistOrder(s, 14.0, 0.8, ang, 0.0), true, bestParent, bestScore);\n        }\n\n        // Randomized multi-start\n        int trial = 0;\n        while (!time_up()) {\n            vector<int> p;\n            int typ = trial % 5;\n\n            if (typ == 0) {\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wA = 0.8 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.08;\n                p = buildProjectionOrder(ang, wA, wP, 1e-3);\n            } else if (typ == 1) {\n                int s = seeds[uniform_int_distribution<int>(0, (int)seeds.size() - 1)(rng)];\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wD = 7.0 + 10.0 * rand01();\n                double wA = 0.6 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.03;\n                p = buildSeedDistOrder(s, wD, wA, ang, wP, 1e-3);\n            } else if (typ == 2) {\n                double wA = 0.8 + 1.2 * rand01();\n                double wDeg = 0.5 + 2.5 * rand01();\n                p = buildBeautyDegreeOrder(wA, wDeg, 1e-3);\n            } else if (typ == 3) {\n                p = buildBeautyOrder(1e-3);\n            } else {\n                p = buildAllRoots();\n            }\n\n            processCandidate(p, remaining_ms() > 700, bestParent, bestScore);\n            ++trial;\n        }\n\n        return bestParent;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M >> solver.H;\n    solver.A.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.A[i];\n\n    solver.edges.resize(solver.M);\n    solver.g.assign(solver.N, {});\n    solver.deg.assign(solver.N, 0);\n    solver.adjMat.assign(solver.N, {});\n\n    for (int i = 0; i < solver.M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        solver.edges[i] = {u, v};\n        solver.g[u].push_back(v);\n        solver.g[v].push_back(u);\n        solver.deg[u]++;\n        solver.deg[v]++;\n        solver.adjMat[u].set(v);\n        solver.adjMat[v].set(u);\n    }\n\n    solver.X.resize(solver.N);\n    solver.Y.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) {\n        cin >> solver.X[i] >> solver.Y[i];\n    }\n\n    vector<int> ans = solver.solve();\n\n    for (int i = 0; i < solver.N; ++i) {\n        if (i) cout << ' ';\n        cout << ans[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAX_ONI = 40;\nstatic constexpr int SIDE = 80;\nstatic constexpr int MAXD = 20;\nstatic constexpr int MAXP = 32;\nstatic constexpr double TL = 1.92;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n} timer_;\n\nmt19937_64 rng_(chrono::steady_clock::now().time_since_epoch().count());\n\ninline int sideL(int r) { return r; }\ninline int sideR(int r) { return 20 + r; }\ninline int sideU(int c) { return 40 + c; }\ninline int sideD(int c) { return 60 + c; }\n\ninline char sideDir(int s) {\n    if (s < 20) return 'L';\n    if (s < 40) return 'R';\n    if (s < 60) return 'U';\n    return 'D';\n}\ninline int sideIdx(int s) {\n    if (s < 20) return s;\n    if (s < 40) return s - 20;\n    if (s < 60) return s - 40;\n    return s - 60;\n}\ninline char revDir(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\nstruct Macro {\n    char d;\n    int p;\n    int k;\n};\n\ninline int macroSide(const Macro& a) {\n    if (a.d == 'L') return sideL(a.p);\n    if (a.d == 'R') return sideR(a.p);\n    if (a.d == 'U') return sideU(a.p);\n    return sideD(a.p);\n}\n\nstruct Board {\n    array<array<char, N>, N> g{};\n    int xcnt = 0;\n};\n\nstruct FinishData {\n    int m = 0;\n    bool safe = true;\n    array<pair<int,int>, MAX_ONI> pos{};\n    array<array<int, 4>, MAX_ONI> candList{};\n    array<int, MAX_ONI> candCnt{};\n    array<array<int, SIDE>, MAX_ONI> depthOf{};\n    array<int, MAX_ONI> minDepth{};\n    array<int, N> firstORow{}, lastORow{}, firstOCol{}, lastOCol{};\n};\n\nstruct State {\n    array<int, MAX_ONI> assign{};\n    array<array<unsigned char, MAXD + 1>, SIDE> cnt{};\n    array<int, SIDE> dep{};\n    array<unsigned long long, SIDE> mem{};\n    int S = 0;\n    int M = 0;\n    int cost() const { return S - M; }\n};\n\nstruct BeamNode {\n    Board b;\n    array<Macro, MAXP> pref{};\n    int plen = 0;\n    int prefixCost = 0;\n    int est = (int)1e9;\n    uint64_t h = 0;\n};\n\nstruct Endpoint {\n    Board b;\n    array<Macro, MAXP> pref{};\n    int plen = 0;\n    int prefixCost = 0;\n    int quickTotal = (int)1e9;\n    uint64_t h = 0;\n};\n\nuint64_t hashBoard(const Board& b) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            h ^= (uint64_t)(unsigned char)b.g[i][j];\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nvoid applyOne(Board& b, char d, int p) {\n    if (d == 'L') {\n        if (b.g[p][0] == 'x') b.xcnt--;\n        for (int j = 0; j + 1 < N; j++) b.g[p][j] = b.g[p][j + 1];\n        b.g[p][N - 1] = '.';\n    } else if (d == 'R') {\n        if (b.g[p][N - 1] == 'x') b.xcnt--;\n        for (int j = N - 1; j >= 1; j--) b.g[p][j] = b.g[p][j - 1];\n        b.g[p][0] = '.';\n    } else if (d == 'U') {\n        if (b.g[0][p] == 'x') b.xcnt--;\n        for (int i = 0; i + 1 < N; i++) b.g[i][p] = b.g[i + 1][p];\n        b.g[N - 1][p] = '.';\n    } else {\n        if (b.g[N - 1][p] == 'x') b.xcnt--;\n        for (int i = N - 1; i >= 1; i--) b.g[i][p] = b.g[i - 1][p];\n        b.g[0][p] = '.';\n    }\n}\n\nvoid applyMacro(Board& b, const Macro& a) {\n    for (int t = 0; t < a.k; t++) applyOne(b, a.d, a.p);\n}\n\nFinishData buildData(const Board& b) {\n    FinishData D;\n    for (int i = 0; i < N; i++) {\n        D.firstORow[i] = N;\n        D.lastORow[i] = -1;\n    }\n    for (int j = 0; j < N; j++) {\n        D.firstOCol[j] = N;\n        D.lastOCol[j] = -1;\n    }\n\n    D.m = 0;\n    D.safe = true;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] == 'o') {\n                D.firstORow[i] = min(D.firstORow[i], j);\n                D.lastORow[i] = max(D.lastORow[i], j);\n                D.firstOCol[j] = min(D.firstOCol[j], i);\n                D.lastOCol[j] = max(D.lastOCol[j], i);\n            }\n        }\n    }\n\n    for (int u = 0; u < MAX_ONI; u++) {\n        D.candCnt[u] = 0;\n        D.minDepth[u] = 1e9;\n        D.depthOf[u].fill(0);\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] != 'x') continue;\n            int u = D.m++;\n            D.pos[u] = {i, j};\n\n            auto addCand = [&](int s, int d) {\n                int c = D.candCnt[u];\n                D.candList[u][c] = s;\n                D.candCnt[u]++;\n                D.depthOf[u][s] = d;\n                D.minDepth[u] = min(D.minDepth[u], d);\n            };\n\n            if (j < D.firstORow[i]) addCand(sideL(i), j + 1);\n            if (j > D.lastORow[i]) addCand(sideR(i), N - j);\n            if (i < D.firstOCol[j]) addCand(sideU(j), i + 1);\n            if (i > D.lastOCol[j]) addCand(sideD(j), N - i);\n\n            if (D.candCnt[u] == 0) D.safe = false;\n        }\n    }\n    return D;\n}\n\nState emptyState() {\n    State st;\n    st.assign.fill(-1);\n    for (int s = 0; s < SIDE; s++) {\n        st.cnt[s].fill(0);\n        st.dep[s] = 0;\n        st.mem[s] = 0ULL;\n    }\n    st.S = 0;\n    st.M = 0;\n    return st;\n}\n\ninline int recomputeM(const State& st) {\n    int m = 0;\n    for (int s = 0; s < SIDE; s++) m = max(m, st.dep[s]);\n    return m;\n}\n\nvoid addAssign(State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    st.assign[u] = s;\n    st.mem[s] |= (1ULL << u);\n    st.cnt[s][d]++;\n    if (d > st.dep[s]) {\n        st.S += 2 * (d - st.dep[s]);\n        st.dep[s] = d;\n    }\n    if (st.dep[s] > st.M) st.M = st.dep[s];\n}\n\nvoid removeAssign(State& st, const FinishData& D, int u) {\n    int s = st.assign[u];\n    if (s < 0) return;\n    int d = D.depthOf[u][s];\n    st.assign[u] = -1;\n    st.mem[s] &= ~(1ULL << u);\n    st.cnt[s][d]--;\n    if (d == st.dep[s] && st.cnt[s][d] == 0) {\n        int nd = st.dep[s];\n        while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n        st.S += 2 * (nd - st.dep[s]);\n        st.dep[s] = nd;\n    }\n    st.M = recomputeM(st);\n}\n\ninline int secondDepthAfterRemoving(const State& st, int s, int remDepth) {\n    if (remDepth != st.dep[s]) return st.dep[s];\n    if (st.cnt[s][remDepth] >= 2) return st.dep[s];\n    int nd = st.dep[s] - 1;\n    while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n    return nd;\n}\n\nint evalAdd(const State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    int nd = max(st.dep[s], d);\n    int newS = st.S + 2 * (nd - st.dep[s]);\n    int newM = max(st.M, nd);\n    return newS - newM;\n}\n\nint evalMove(const State& st, const FinishData& D, int u, int ns) {\n    int os = st.assign[u];\n    if (os == ns) return st.cost();\n\n    int od = D.depthOf[u][os];\n    int nd = D.depthOf[u][ns];\n    int depOldAfter = secondDepthAfterRemoving(st, os, od);\n    int depNewAfter = max(st.dep[ns], nd);\n\n    int newS = st.S\n        + 2 * (depOldAfter - st.dep[os])\n        + 2 * (depNewAfter - st.dep[ns]);\n\n    int newM = 0;\n    for (int s = 0; s < SIDE; s++) {\n        int d = st.dep[s];\n        if (s == os) d = depOldAfter;\n        else if (s == ns) d = depNewAfter;\n        newM = max(newM, d);\n    }\n    return newS - newM;\n}\n\nvector<int> makeOrderDifficulty(const FinishData& D, bool randomized) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    vector<uint64_t> key(D.m);\n    for (int i = 0; i < D.m; i++) key[i] = rng_();\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D.candCnt[a] != D.candCnt[b]) return D.candCnt[a] < D.candCnt[b];\n        if (D.minDepth[a] != D.minDepth[b]) return D.minDepth[a] > D.minDepth[b];\n        if (randomized) return key[a] < key[b];\n        return a < b;\n    });\n    return ord;\n}\n\nvector<int> makeOrderRandom(int m) {\n    vector<int> ord(m);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng_);\n    return ord;\n}\n\nState buildGreedy(const FinishData& D, const vector<int>& ord, bool randomized) {\n    State st = emptyState();\n    for (int u : ord) {\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            opts[oc++] = {evalAdd(st, D, u, s), s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        int choose = opts[0].second;\n        if (randomized && oc > 1) {\n            int lim = 1;\n            while (lim < oc && opts[lim].first <= opts[0].first + 1) ++lim;\n            lim = min(lim, 3);\n            choose = opts[(int)(rng_() % lim)].second;\n        }\n        addAssign(st, D, u, choose);\n    }\n    return st;\n}\n\nState buildMinDepthState(const FinishData& D) {\n    State st = emptyState();\n    for (int u = 0; u < D.m; u++) {\n        int bestS = D.candList[u][0];\n        int bestD = D.depthOf[u][bestS];\n        for (int it = 1; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            int d = D.depthOf[u][s];\n            if (d < bestD || (d == bestD && s < bestS)) {\n                bestD = d;\n                bestS = s;\n            }\n        }\n        addAssign(st, D, u, bestS);\n    }\n    return st;\n}\n\nvoid local1(const FinishData& D, State& st, int rounds = 2) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    for (int rep = 0; rep < rounds; rep++) {\n        bool improved = false;\n        for (int u : ord) {\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvector<int> membersOfMask(unsigned long long mask) {\n    vector<int> res;\n    while (mask) {\n        int b = __builtin_ctzll(mask);\n        res.push_back(b);\n        mask &= mask - 1;\n    }\n    return res;\n}\n\nbool exactReoptSubset(State& st, const FinishData& D, vector<int> subset, int forbidSide, double deadline) {\n    if (subset.empty()) return false;\n\n    State original = st;\n    for (int u : subset) removeAssign(st, D, u);\n\n    for (int u : subset) {\n        int ok = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != forbidSide) ok++;\n        }\n        if (ok == 0) {\n            st = original;\n            return false;\n        }\n    }\n\n    sort(subset.begin(), subset.end(), [&](int a, int b) {\n        int ca = 0, cb = 0;\n        for (int it = 0; it < D.candCnt[a]; it++) if (D.candList[a][it] != forbidSide) ca++;\n        for (int it = 0; it < D.candCnt[b]; it++) if (D.candList[b][it] != forbidSide) cb++;\n        if (ca != cb) return ca < cb;\n        return D.minDepth[a] > D.minDepth[b];\n    });\n\n    int bestCost = original.cost();\n    State bestState = original;\n    long long nodes = 0;\n    bool timeout = false;\n\n    function<void(int)> dfs = [&](int idx) {\n        if ((nodes++ & 1023LL) == 0 && timer_.elapsed() >= deadline) {\n            timeout = true;\n            return;\n        }\n        int curCost = st.cost();\n        if (curCost >= bestCost) return;\n        if (idx == (int)subset.size()) {\n            bestCost = curCost;\n            bestState = st;\n            return;\n        }\n\n        int u = subset[idx];\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            if (s == forbidSide) continue;\n            int c = evalAdd(st, D, u, s);\n            if (c < bestCost) opts[oc++] = {c, s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        for (int i = 0; i < oc; i++) {\n            int s = opts[i].second;\n            int c = opts[i].first;\n            if (c >= bestCost) break;\n            addAssign(st, D, u, s);\n            dfs(idx + 1);\n            removeAssign(st, D, u);\n            if (timeout) return;\n        }\n    };\n\n    dfs(0);\n    st = bestState;\n    return st.cost() < original.cost();\n}\n\nbool exactCloseOneSide(State& st, const FinishData& D, int side, double deadline) {\n    int sz = __builtin_popcountll(st.mem[side]);\n    if (sz <= 1 || sz > 8) return false;\n    vector<int> subset = membersOfMask(st.mem[side]);\n    for (int u : subset) {\n        bool alt = false;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != side) { alt = true; break; }\n        }\n        if (!alt) return false;\n    }\n    return exactReoptSubset(st, D, subset, side, deadline);\n}\n\nvoid localImproveStrong(const FinishData& D, State& st, double deadline) {\n    while (timer_.elapsed() < deadline) {\n        bool improved = false;\n\n        vector<int> ord(D.m);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng_);\n\n        for (int u : ord) {\n            if (timer_.elapsed() >= deadline) return;\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        vector<int> sides;\n        for (int s = 0; s < SIDE; s++) {\n            int sz = __builtin_popcountll(st.mem[s]);\n            if (sz >= 2 && sz <= 8) sides.push_back(s);\n        }\n        shuffle(sides.begin(), sides.end(), rng_);\n        for (int s : sides) {\n            if (timer_.elapsed() >= deadline) return;\n            if (exactCloseOneSide(st, D, s, deadline)) {\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nState quickSolve(const FinishData& D) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    State best = buildGreedy(D, makeOrderDifficulty(D, false), false);\n    local1(D, best, 2);\n\n    State alt = buildMinDepthState(D);\n    local1(D, alt, 2);\n    if (alt.cost() < best.cost()) best = alt;\n\n    return best;\n}\n\nState strongSolve(const FinishData& D, double deadline) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    State best = quickSolve(D);\n    localImproveStrong(D, best, deadline);\n\n    int iter = 0;\n    while (timer_.elapsed() < deadline) {\n        State st;\n        if ((iter & 1) == 0) st = buildGreedy(D, makeOrderDifficulty(D, true), true);\n        else st = buildGreedy(D, makeOrderRandom(D.m), true);\n        localImproveStrong(D, st, deadline);\n        if (st.cost() < best.cost()) best = st;\n        iter++;\n    }\n    return best;\n}\n\nvoid emitSide(vector<pair<char,int>>& ops, int side, int depth, bool restore) {\n    char d = sideDir(side);\n    char rd = revDir(d);\n    int p = sideIdx(side);\n    for (int t = 0; t < depth; t++) ops.push_back({d, p});\n    if (restore) {\n        for (int t = 0; t < depth; t++) ops.push_back({rd, p});\n    }\n}\n\nvector<pair<char,int>> buildFinishOps(const State& st) {\n    vector<int> used;\n    for (int s = 0; s < SIDE; s++) if (st.dep[s] > 0) used.push_back(s);\n    vector<pair<char,int>> ops;\n    if (used.empty()) return ops;\n\n    int finalSide = used[0];\n    for (int s : used) {\n        if (st.dep[s] > st.dep[finalSide]) finalSide = s;\n    }\n\n    sort(used.begin(), used.end(), [&](int a, int b) {\n        if (st.dep[a] != st.dep[b]) return st.dep[a] < st.dep[b];\n        return a < b;\n    });\n\n    for (int s : used) {\n        if (s == finalSide) continue;\n        emitSide(ops, s, st.dep[s], true);\n    }\n    emitSide(ops, finalSide, st.dep[finalSide], false);\n    return ops;\n}\n\nvector<pair<char,int>> buildPlan(const array<Macro, MAXP>& pref, int plen, const State& st) {\n    vector<pair<char,int>> ops;\n    for (int i = 0; i < plen; i++) {\n        for (int t = 0; t < pref[i].k; t++) ops.push_back({pref[i].d, pref[i].p});\n    }\n    auto fin = buildFinishOps(st);\n    ops.insert(ops.end(), fin.begin(), fin.end());\n    return ops;\n}\n\npair<int,int> simulate(const Board& init, const vector<pair<char,int>>& ops) {\n    Board b = init;\n    int removedO = 0;\n    for (auto [d, p] : ops) {\n        if (d == 'L') {\n            if (b.g[p][0] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'R') {\n            if (b.g[p][N - 1] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'U') {\n            if (b.g[0][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else {\n            if (b.g[N - 1][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        }\n    }\n    return {b.xcnt, removedO};\n}\n\nstruct ScoredAction {\n    Macro a;\n    int score;\n};\n\nvector<Macro> enumerateActions(const Board& b, const FinishData& D, int cap = 64) {\n    array<int, N> rowX{}, colX{};\n    for (int i = 0; i < N; i++) rowX[i] = 0;\n    for (int j = 0; j < N; j++) colX[j] = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] == 'x') {\n                rowX[i]++;\n                colX[j]++;\n            }\n        }\n    }\n\n    bool seen[SIDE][MAXD + 1];\n    for (int s = 0; s < SIDE; s++) for (int d = 0; d <= MAXD; d++) seen[s][d] = false;\n\n    vector<ScoredAction> ret;\n    ret.reserve(256);\n\n    auto pushAct = [&](Macro a, int score) {\n        int s = macroSide(a);\n        if (a.k <= 0 || a.k > 20) return;\n        if (seen[s][a.k]) return;\n        seen[s][a.k] = true;\n        ret.push_back({a, score});\n    };\n\n    // Direct removing macros on rows.\n    for (int r = 0; r < N; r++) {\n        int limL = D.firstORow[r];\n        int removed = 0;\n        bool hasXSafe = false;\n        for (int j = 0; j < limL; j++) {\n            if (b.g[r][j] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'L', r, j + 1}, 220 * removed - 10 * (j + 1));\n            }\n        }\n        if (!hasXSafe && limL > 1 && rowX[r] > 0) {\n            // Empty setup: push the clean prefix out until the first 'o' reaches edge.\n            pushAct({'L', r, limL}, 18 * rowX[r] - 5 * limL);\n        }\n\n        int limR = (D.lastORow[r] == -1 ? N : N - 1 - D.lastORow[r]);\n        removed = 0;\n        hasXSafe = false;\n        for (int j = N - 1; j >= N - limR; j--) {\n            if (b.g[r][j] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'R', r, N - j}, 220 * removed - 10 * (N - j));\n            }\n        }\n        if (!hasXSafe && limR > 1 && rowX[r] > 0) {\n            pushAct({'R', r, limR}, 18 * rowX[r] - 5 * limR);\n        }\n    }\n\n    // Direct removing macros on columns.\n    for (int c = 0; c < N; c++) {\n        int limU = D.firstOCol[c];\n        int removed = 0;\n        bool hasXSafe = false;\n        for (int i = 0; i < limU; i++) {\n            if (b.g[i][c] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'U', c, i + 1}, 220 * removed - 10 * (i + 1));\n            }\n        }\n        if (!hasXSafe && limU > 1 && colX[c] > 0) {\n            pushAct({'U', c, limU}, 18 * colX[c] - 5 * limU);\n        }\n\n        int limD = (D.lastOCol[c] == -1 ? N : N - 1 - D.lastOCol[c]);\n        removed = 0;\n        hasXSafe = false;\n        for (int i = N - 1; i >= N - limD; i--) {\n            if (b.g[i][c] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'D', c, N - i}, 220 * removed - 10 * (N - i));\n            }\n        }\n        if (!hasXSafe && limD > 1 && colX[c] > 0) {\n            pushAct({'D', c, limD}, 18 * colX[c] - 5 * limD);\n        }\n    }\n\n    // Safe 1-step setup shifts.\n    for (int r = 0; r < N; r++) {\n        if (rowX[r] > 0) {\n            if (b.g[r][0] != 'o') pushAct({'L', r, 1}, 14 * rowX[r] - 4);\n            if (b.g[r][N - 1] != 'o') pushAct({'R', r, 1}, 14 * rowX[r] - 4);\n        }\n    }\n    for (int c = 0; c < N; c++) {\n        if (colX[c] > 0) {\n            if (b.g[0][c] != 'o') pushAct({'U', c, 1}, 14 * colX[c] - 4);\n            if (b.g[N - 1][c] != 'o') pushAct({'D', c, 1}, 14 * colX[c] - 4);\n        }\n    }\n\n    sort(ret.begin(), ret.end(), [&](const ScoredAction& A, const ScoredAction& B) {\n        if (A.score != B.score) return A.score > B.score;\n        if (A.a.k != B.a.k) return A.a.k < B.a.k;\n        if (A.a.d != B.a.d) return A.a.d < B.a.d;\n        return A.a.p < B.a.p;\n    });\n\n    if ((int)ret.size() > cap) ret.resize(cap);\n    vector<Macro> acts;\n    acts.reserve(ret.size());\n    for (auto& x : ret) acts.push_back(x.a);\n    return acts;\n}\n\nvoid addEndpoint(vector<Endpoint>& eps, const Endpoint& e, int keep = 20) {\n    for (auto& x : eps) {\n        if (x.h == e.h) {\n            if (e.quickTotal < x.quickTotal) x = e;\n            return;\n        }\n    }\n    eps.push_back(e);\n    sort(eps.begin(), eps.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n        return a.b.xcnt < b.b.xcnt;\n    });\n    if ((int)eps.size() > keep) eps.resize(keep);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n_in;\n    cin >> n_in;\n\n    Board init;\n    init.xcnt = 0;\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) {\n            init.g[i][j] = s[j];\n            if (s[j] == 'x') init.xcnt++;\n        }\n    }\n\n    vector<pair<char,int>> bestOps;\n    int bestLen = (int)1e9;\n\n    // Baseline quick and strong finish from the initial board.\n    FinishData D0 = buildData(init);\n    if (D0.safe) {\n        State q0 = quickSolve(D0);\n        auto ops = buildFinishOps(q0);\n        auto [rx, ry] = simulate(init, ops);\n        if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) {\n            bestOps = ops;\n            bestLen = (int)ops.size();\n        }\n\n        double baseBudget = min(0.16, TL * 0.10);\n        State s0 = strongSolve(D0, min(TL - 0.05, timer_.elapsed() + baseBudget));\n        auto ops2 = buildFinishOps(s0);\n        auto [rx2, ry2] = simulate(init, ops2);\n        if ((int)ops2.size() <= 4 * N * N && rx2 == 0 && ry2 == 0) {\n            if ((int)ops2.size() < bestLen) {\n                bestOps = ops2;\n                bestLen = (int)ops2.size();\n            }\n        }\n    }\n\n    // Beam search over safe one-way prefixes.\n    vector<Endpoint> endpoints;\n    {\n        Endpoint ep;\n        ep.b = init;\n        ep.plen = 0;\n        ep.prefixCost = 0;\n        ep.quickTotal = bestLen;\n        ep.h = hashBoard(init);\n        addEndpoint(endpoints, ep, 24);\n    }\n\n    vector<BeamNode> beam;\n    {\n        BeamNode st;\n        st.b = init;\n        st.plen = 0;\n        st.prefixCost = 0;\n        st.est = bestLen;\n        st.h = hashBoard(init);\n        beam.push_back(st);\n    }\n\n    unordered_map<uint64_t, int> bestPrefixCost;\n    bestPrefixCost.reserve(1 << 15);\n    bestPrefixCost[hashBoard(init)] = 0;\n\n    const int BEAM_WIDTH = 18;\n    const int BEAM_DEPTH = 16;\n    double beamEnd = 1.48;\n\n    for (int dep = 0; dep < BEAM_DEPTH && timer_.elapsed() < beamEnd && !beam.empty(); dep++) {\n        vector<BeamNode> cand;\n        cand.reserve(BEAM_WIDTH * 80);\n\n        for (const auto& node : beam) {\n            if (timer_.elapsed() >= beamEnd) break;\n            FinishData D = buildData(node.b);\n            if (!D.safe) continue;\n\n            auto acts = enumerateActions(node.b, D, 64);\n\n            for (const auto& a : acts) {\n                if (timer_.elapsed() >= beamEnd) break;\n                if (node.plen >= MAXP) continue;\n\n                BeamNode child = node;\n                applyMacro(child.b, a);\n                child.pref[child.plen++] = a;\n                child.prefixCost += a.k;\n                if (child.prefixCost >= 4 * N * N) continue;\n\n                child.h = hashBoard(child.b);\n                auto it = bestPrefixCost.find(child.h);\n                if (it != bestPrefixCost.end() && it->second <= child.prefixCost) continue;\n\n                FinishData ND = buildData(child.b);\n                if (!ND.safe) continue;\n\n                State qst = quickSolve(ND);\n                child.est = child.prefixCost + qst.cost();\n\n                auto it2 = bestPrefixCost.find(child.h);\n                if (it2 == bestPrefixCost.end() || child.prefixCost < it2->second) {\n                    bestPrefixCost[child.h] = child.prefixCost;\n                }\n\n                // Immediate valid answer.\n                if (child.est < bestLen) {\n                    auto ops = buildPlan(child.pref, child.plen, qst);\n                    auto [rx, ry] = simulate(init, ops);\n                    if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) {\n                        bestLen = (int)ops.size();\n                        bestOps = std::move(ops);\n                    }\n                }\n\n                Endpoint ep;\n                ep.b = child.b;\n                ep.pref = child.pref;\n                ep.plen = child.plen;\n                ep.prefixCost = child.prefixCost;\n                ep.quickTotal = child.est;\n                ep.h = child.h;\n                addEndpoint(endpoints, ep, 24);\n\n                cand.push_back(std::move(child));\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [&](const BeamNode& a, const BeamNode& b) {\n            if (a.est != b.est) return a.est < b.est;\n            if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n            if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n            return a.plen < b.plen;\n        });\n\n        vector<BeamNode> nxt;\n        nxt.reserve(BEAM_WIDTH);\n        unordered_set<uint64_t> used;\n        used.reserve(BEAM_WIDTH * 4);\n\n        for (auto& x : cand) {\n            if ((int)nxt.size() >= BEAM_WIDTH) break;\n            if (used.insert(x.h).second) nxt.push_back(std::move(x));\n        }\n        beam.swap(nxt);\n    }\n\n    // Stronger finishing on promising beam endpoints.\n    sort(endpoints.begin(), endpoints.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n        return a.b.xcnt < b.b.xcnt;\n    });\n\n    for (int i = 0; i < (int)endpoints.size(); i++) {\n        if (timer_.elapsed() >= TL - 0.03) break;\n\n        double remain = TL - 0.02 - timer_.elapsed();\n        int left = (int)endpoints.size() - i;\n        double budget = min(0.14, max(0.03, remain / max(1, left)));\n\n        FinishData D = buildData(endpoints[i].b);\n        if (!D.safe) continue;\n\n        State st = strongSolve(D, min(TL - 0.02, timer_.elapsed() + budget));\n        int total = endpoints[i].prefixCost + st.cost();\n        if (total >= bestLen) continue;\n\n        auto ops = buildPlan(endpoints[i].pref, endpoints[i].plen, st);\n        auto [rx, ry] = simulate(init, ops);\n        if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) {\n            if ((int)ops.size() < bestLen) {\n                bestLen = (int)ops.size();\n                bestOps = std::move(ops);\n            }\n        }\n    }\n\n    // Final safety fallback.\n    if (bestOps.empty()) {\n        FinishData D = buildData(init);\n        State st = quickSolve(D);\n        bestOps = buildFinishOps(st);\n    } else {\n        auto [rx, ry] = simulate(init, bestOps);\n        if (!((int)bestOps.size() <= 4 * N * N && rx == 0 && ry == 0)) {\n            FinishData D = buildData(init);\n            State st = quickSolve(D);\n            auto ops = buildFinishOps(st);\n            auto [rx2, ry2] = simulate(init, ops);\n            if ((int)ops.size() <= 4 * N * N && rx2 == 0 && ry2 == 0) bestOps = ops;\n        }\n    }\n\n    for (auto [d, p] : bestOps) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct SimResult {\n    vector<int> cnt;\n    int end_node;\n    ll err;\n};\n\nstruct BuildResult {\n    vector<int> a, b;\n    ll approx_cost;\n};\n\nstruct Candidate {\n    vector<int> order, a, b, cnt;\n    int end_node = 0;\n    ll err = (1LL << 60);\n    ll approx_cost = (1LL << 60);\n};\n\nint N, Lw;\nvector<int> T;\n\nstatic inline ll absll(ll x) { return x >= 0 ? x : -x; }\n\nbool betterCand(const Candidate& x, const Candidate& y) {\n    if (x.err != y.err) return x.err < y.err;\n    return x.approx_cost < y.approx_cost;\n}\n\nvector<int> normalize_order(vector<int> ord) {\n    int pos = find(ord.begin(), ord.end(), 0) - ord.begin();\n    rotate(ord.begin(), ord.begin() + pos, ord.end());\n    return ord;\n}\n\nvector<int> next_from_order(const vector<int>& order) {\n    vector<int> nxt(N);\n    for (int i = 0; i < N; ++i) nxt[order[i]] = order[(i + 1) % N];\n    return nxt;\n}\n\nvector<int> prev_from_order(const vector<int>& order) {\n    vector<int> prv(N);\n    for (int i = 0; i < N; ++i) prv[order[(i + 1) % N]] = order[i];\n    return prv;\n}\n\nll calc_cost(const vector<int>& assign, const vector<int>& item, const vector<int>& need, vector<int>* load_out = nullptr) {\n    vector<int> load(N, 0);\n    for (int i = 0; i < N; ++i) load[assign[i]] += item[i];\n    ll cost = 0;\n    for (int j = 0; j < N; ++j) cost += absll((ll)load[j] - need[j]);\n    if (load_out) *load_out = load;\n    return cost;\n}\n\n// ---------- fast cycle-order surrogate cost ----------\nll edge_cost_fast(int i, int j, const vector<int>& est) {\n    ll half_from_i = (est[i] + 1) / 2;\n    ll cap_j = T[j] - (j == 0 ? 1 : 0);\n    if (cap_j < 0) cap_j = 0;\n    ll ideal = (cap_j + 1) / 2;\n    ll over = max(0LL, half_from_i - cap_j);\n    ll sim = absll((ll)est[i] - est[j]);\n    return over * 20 + absll(half_from_i - ideal) * 4 + sim;\n}\n\nll order_cost_fast(const vector<int>& ord, const vector<int>& est) {\n    ll c = 0;\n    for (int k = 0; k < N; ++k) {\n        int i = ord[k];\n        int j = ord[(k + 1) % N];\n        c += edge_cost_fast(i, j, est);\n    }\n    return c;\n}\n\nvector<int> mutate_order_random(const vector<int>& ord, mt19937& rng) {\n    vector<int> res = ord;\n    int op = (int)(rng() % 3);\n\n    if (op == 0) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) swap(res[x], res[y]);\n    } else if (op == 1) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) {\n            int v = res[x];\n            res.erase(res.begin() + x);\n            if (y > x) --y;\n            res.insert(res.begin() + y, v);\n        }\n    } else {\n        int l = 1 + (int)(rng() % (N - 1));\n        int r = 1 + (int)(rng() % (N - 1));\n        if (l > r) swap(l, r);\n        if (l == r) r = min(N - 1, l + 1);\n        reverse(res.begin() + l, res.begin() + r + 1);\n    }\n    return res;\n}\n\nvector<int> optimize_order_fast(vector<int> ord, const vector<int>& est, mt19937& rng, int iters, double temp0) {\n    ord = normalize_order(ord);\n    ll cur = order_cost_fast(ord, est);\n    vector<int> best = ord;\n    ll bestc = cur;\n\n    uniform_real_distribution<double> U(0.0, 1.0);\n    double temp = temp0;\n    double temp1 = 1.0;\n    double alpha = pow(temp1 / temp0, 1.0 / max(1, iters));\n\n    for (int iter = 0; iter < iters; ++iter) {\n        vector<int> cand = mutate_order_random(ord, rng);\n        ll nc = order_cost_fast(cand, est);\n        if (nc < cur || U(rng) < exp((double)(cur - nc) / max(1.0, temp))) {\n            ord.swap(cand);\n            cur = nc;\n            if (cur < bestc) {\n                bestc = cur;\n                best = ord;\n            }\n        }\n        temp *= alpha;\n    }\n    return best;\n}\n\n// ---------- assignment builders ----------\nvector<int> init_dp_partition(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N), tgt_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    iota(tgt_ord.begin(), tgt_ord.end(), 0);\n\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] < item[b];\n        return a < b;\n    });\n    sort(tgt_ord.begin(), tgt_ord.end(), [&](int a, int b) {\n        if (need[a] != need[b]) return need[a] < need[b];\n        return a < b;\n    });\n\n    vector<ll> pref(N + 1, 0);\n    for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + item[src_ord[i]];\n\n    const ll INF = (1LL << 60);\n    vector<vector<ll>> dp(N + 1, vector<ll>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int k = 0; k < N; ++k) {\n        for (int i = 0; i <= N; ++i) {\n            if (dp[k][i] >= INF) continue;\n            for (int j = i; j <= N; ++j) {\n                ll segsum = pref[j] - pref[i];\n                ll nd = dp[k][i] + absll(segsum - (ll)need[tgt_ord[k]]);\n                if (nd < dp[k + 1][j]) {\n                    dp[k + 1][j] = nd;\n                    par[k + 1][j] = i;\n                }\n            }\n        }\n    }\n\n    vector<int> assign(N, 0);\n    int cur = N;\n    for (int k = N - 1; k >= 0; --k) {\n        int prv = par[k + 1][cur];\n        if (prv < 0) prv = 0;\n        for (int p = prv; p < cur; ++p) assign[src_ord[p]] = tgt_ord[k];\n        cur = prv;\n    }\n    return assign;\n}\n\nvector<int> init_greedy(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] > item[b];\n        return a < b;\n    });\n\n    vector<int> assign(N, 0), load(N, 0);\n\n    for (int s : src_ord) {\n        ll best_delta = (1LL << 60);\n        int best_t = 0;\n        for (int t = 0; t < N; ++t) {\n            ll before = absll((ll)load[t] - need[t]);\n            ll after = absll((ll)load[t] + item[s] - need[t]);\n            ll delta = after - before;\n            ll deficit = (ll)need[t] - load[t];\n            ll best_deficit = (ll)need[best_t] - load[best_t];\n            if (delta < best_delta ||\n                (delta == best_delta && deficit > best_deficit) ||\n                (delta == best_delta && deficit == best_deficit && t < best_t)) {\n                best_delta = delta;\n                best_t = t;\n            }\n        }\n        assign[s] = best_t;\n        load[best_t] += item[s];\n    }\n    return assign;\n}\n\nll local_search_assign(vector<int>& assign, const vector<int>& item, const vector<int>& need) {\n    vector<int> load;\n    ll total = calc_cost(assign, item, need, &load);\n\n    const int MAX_IT = 80;\n    for (int iter = 0; iter < MAX_IT; ++iter) {\n        vector<ll> base(N);\n        for (int j = 0; j < N; ++j) base[j] = absll((ll)load[j] - need[j]);\n\n        ll best_delta = 0;\n        int best_kind = 0;\n        int bi = -1, bj = -1, bk = -1;\n\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i], w = item[i];\n            if (w == 0) continue;\n            for (int v = 0; v < N; ++v) if (v != u) {\n                ll delta = 0;\n                delta += absll((ll)load[u] - w - need[u]) - base[u];\n                delta += absll((ll)load[v] + w - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 1;\n                    bi = i; bj = v;\n                }\n            }\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i], wi = item[i];\n            for (int k = i + 1; k < N; ++k) {\n                int v = assign[k];\n                if (u == v) continue;\n                int wk = item[k];\n                ll delta = 0;\n                delta += absll((ll)load[u] - wi + wk - need[u]) - base[u];\n                delta += absll((ll)load[v] - wk + wi - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 2;\n                    bi = i; bk = k;\n                }\n            }\n        }\n\n        if (best_kind == 0) break;\n\n        if (best_kind == 1) {\n            int i = bi, v = bj;\n            int u = assign[i], w = item[i];\n            load[u] -= w;\n            load[v] += w;\n            assign[i] = v;\n            total += best_delta;\n        } else {\n            int i = bi, k = bk;\n            int u = assign[i], v = assign[k];\n            int wi = item[i], wk = item[k];\n            load[u] = load[u] - wi + wk;\n            load[v] = load[v] - wk + wi;\n            swap(assign[i], assign[k]);\n            total += best_delta;\n        }\n    }\n    return total;\n}\n\n// ---------- build graph from fixed order ----------\nBuildResult build_graph(const vector<int>& order, const vector<int>& est_cnt, bool exact_end, int end_node) {\n    vector<int> nxt = next_from_order(order);\n    vector<int> prv = prev_from_order(order);\n\n    vector<int> out = est_cnt;\n    if (exact_end && 0 <= end_node && end_node < N) out[end_node]--;\n\n    vector<int> fixed_a(N), item_b(N), need(N);\n    for (int i = 0; i < N; ++i) {\n        if (out[i] < 0) out[i] = 0;\n        fixed_a[i] = (out[i] + 1) / 2;\n        item_b[i] = out[i] / 2;\n    }\n    for (int j = 0; j < N; ++j) {\n        need[j] = T[j] - (j == 0 ? 1 : 0) - fixed_a[prv[j]];\n    }\n\n    vector<int> assign1 = init_dp_partition(item_b, need);\n    ll cost1 = local_search_assign(assign1, item_b, need);\n\n    vector<int> assign2 = init_greedy(item_b, need);\n    ll cost2 = local_search_assign(assign2, item_b, need);\n\n    BuildResult res;\n    res.a = move(nxt);\n    if (cost1 <= cost2) {\n        res.b = move(assign1);\n        res.approx_cost = cost1;\n    } else {\n        res.b = move(assign2);\n        res.approx_cost = cost2;\n    }\n    return res;\n}\n\n// ---------- exact simulation ----------\nSimResult simulate_graph(const vector<int>& a, const vector<int>& b) {\n    vector<int> cnt(N, 0);\n    int cur = 0, end_node = 0;\n    for (int week = 0; week < Lw; ++week) {\n        ++cnt[cur];\n        end_node = cur;\n        if (week + 1 == Lw) break;\n        cur = (cnt[cur] & 1) ? a[cur] : b[cur];\n    }\n    ll err = 0;\n    for (int i = 0; i < N; ++i) err += absll((ll)cnt[i] - T[i]);\n    return {cnt, end_node, err};\n}\n\nCandidate make_candidate(const vector<int>& order, const vector<int>& a, const vector<int>& b, ll approx_cost) {\n    SimResult sr = simulate_graph(a, b);\n    Candidate c;\n    c.order = order;\n    c.a = a;\n    c.b = b;\n    c.cnt = sr.cnt;\n    c.end_node = sr.end_node;\n    c.err = sr.err;\n    c.approx_cost = approx_cost;\n    return c;\n}\n\nCandidate evaluate_order(const vector<int>& order, const vector<int>& init_est, bool exact_end_init, int end_init, int refine_rounds) {\n    BuildResult br = build_graph(order, init_est, exact_end_init, end_init);\n    Candidate cur = make_candidate(order, br.a, br.b, br.approx_cost);\n    Candidate best = cur;\n\n    for (int it = 0; it < refine_rounds; ++it) {\n        BuildResult br2 = build_graph(order, cur.cnt, true, cur.end_node);\n        Candidate nxt = make_candidate(order, br2.a, br2.b, br2.approx_cost);\n        if (betterCand(nxt, cur)) {\n            cur = nxt;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- order generators ----------\nvector<int> sorted_order(bool desc) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return desc ? (T[a] > T[b]) : (T[a] < T[b]);\n        return a < b;\n    });\n    return normalize_order(ord);\n}\n\nvector<int> nearest_neighbor_order(int start, bool half_cost_mode) {\n    vector<int> ord;\n    vector<int> used(N, 0);\n    ord.reserve(N);\n    ord.push_back(start);\n    used[start] = 1;\n    int cur = start;\n\n    for (int step = 1; step < N; ++step) {\n        int best = -1;\n        ll best1 = (1LL << 60), best2 = (1LL << 60);\n        for (int v = 0; v < N; ++v) if (!used[v]) {\n            ll c1, c2;\n            if (!half_cost_mode) {\n                c1 = absll((ll)T[cur] - T[v]);\n                c2 = 0;\n            } else {\n                c1 = max(0, (T[cur] + 1) / 2 - T[v]);\n                c2 = absll((ll)T[cur] - T[v]);\n            }\n            if (best == -1 || c1 < best1 || (c1 == best1 && c2 < best2) || (c1 == best1 && c2 == best2 && v < best)) {\n                best = v;\n                best1 = c1;\n                best2 = c2;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return normalize_order(ord);\n}\n\nvector<int> median_out_order(const vector<int>& base_sorted) {\n    vector<int> ord;\n    ord.reserve(N);\n    int mid = N / 2;\n    ord.push_back(base_sorted[mid]);\n    for (int d = 1; (int)ord.size() < N; ++d) {\n        if (mid - d >= 0) ord.push_back(base_sorted[mid - d]);\n        if ((int)ord.size() >= N) break;\n        if (mid + d < N) ord.push_back(base_sorted[mid + d]);\n    }\n    return normalize_order(ord);\n}\n\nvector<int> alternating_low_high_order() {\n    vector<int> s(N);\n    iota(s.begin(), s.end(), 0);\n    sort(s.begin(), s.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return T[a] < T[b];\n        return a < b;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    int l = 0, r = N - 1;\n    while (l <= r) {\n        ord.push_back(s[l++]);\n        if (l <= r) ord.push_back(s[r--]);\n    }\n    return normalize_order(ord);\n}\n\nvoid add_order_if_new(vector<vector<int>>& orders, set<vector<int>>& seen, vector<int> ord) {\n    ord = normalize_order(ord);\n    if (seen.insert(ord).second) orders.push_back(ord);\n}\n\n// ---------- exact local improvement on order ----------\nCandidate improve_candidate_order(Candidate start, mt19937& rng) {\n    Candidate best = start;\n    Candidate cur = start;\n    set<vector<int>> tried;\n    tried.insert(cur.order);\n\n    {\n        auto jumped = optimize_order_fast(cur.order, cur.cnt, rng, 900, 2500.0);\n        if (!tried.count(jumped)) {\n            tried.insert(jumped);\n            Candidate cand = evaluate_order(jumped, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, cur)) cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n\n    for (int iter = 0; iter < 10; ++iter) {\n        vector<int> chosen;\n        ll best_fast = (1LL << 60);\n\n        for (int t = 0; t < 5; ++t) {\n            auto m = mutate_order_random(cur.order, rng);\n            if (tried.count(m)) continue;\n            ll fc = order_cost_fast(m, cur.cnt);\n            if (fc < best_fast) {\n                best_fast = fc;\n                chosen = move(m);\n            }\n        }\n        if (chosen.empty()) continue;\n        tried.insert(chosen);\n\n        Candidate cand = evaluate_order(chosen, cur.cnt, true, cur.end_node, 1);\n        if (betterCand(cand, cur)) {\n            cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n    return best;\n}\n\n// ---------- end-node refinement ----------\nCandidate refine_endnode_candidate(const Candidate& base) {\n    if (base.order.empty()) return base;\n\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> cand_e;\n    cand_e.push_back(base.end_node);\n    cand_e.push_back(0);\n\n    vector<int> def = ids, ex = ids;\n    sort(def.begin(), def.end(), [&](int a, int b) {\n        ll ra = (ll)T[a] - base.cnt[a];\n        ll rb = (ll)T[b] - base.cnt[b];\n        if (ra != rb) return ra > rb;\n        return a < b;\n    });\n    sort(ex.begin(), ex.end(), [&](int a, int b) {\n        ll ra = (ll)base.cnt[a] - T[a];\n        ll rb = (ll)base.cnt[b] - T[b];\n        if (ra != rb) return ra > rb;\n        return a < b;\n    });\n\n    for (int i = 0; i < 8; ++i) cand_e.push_back(def[i]);\n    for (int i = 0; i < 4; ++i) cand_e.push_back(ex[i]);\n\n    sort(cand_e.begin(), cand_e.end());\n    cand_e.erase(unique(cand_e.begin(), cand_e.end()), cand_e.end());\n\n    Candidate best = base;\n    for (int e : cand_e) {\n        Candidate c = evaluate_order(base.order, base.cnt, true, e, 1);\n        if (betterCand(c, best)) best = c;\n    }\n    return best;\n}\n\n// ---------- local graph repair: b-moves ----------\nstruct MoveCand {\n    ll approx_delta;\n    int type; // 0=bmove, 1=amove, 2=bswap\n    int i, v, k;\n};\n\nCandidate local_search_b_moves(Candidate cur, int rounds = 4, int exactTop = 16) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useB(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useB[i] = dep[i] / 2;\n        }\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            ll ra = (ll)T[a] - cur.cnt[a];\n            ll rb = (ll)T[b] - cur.cnt[b];\n            if (ra != rb) return ra > rb;\n            return a < b;\n        });\n\n        vector<int> tgt;\n        for (int k = 0; k < 10; ++k) tgt.push_back(ids[k]);\n        tgt.push_back(0);\n        sort(tgt.begin(), tgt.end());\n        tgt.erase(unique(tgt.begin(), tgt.end()), tgt.end());\n\n        vector<MoveCand> moves;\n        for (int i = 0; i < N; ++i) {\n            int w = useB[i];\n            if (w == 0) continue;\n            int old = cur.b[i];\n            for (int v : tgt) {\n                if (v == old) continue;\n                ll before = absll((ll)cur.cnt[old] - T[old]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[old] - w - T[old]) + absll((ll)cur.cnt[v] + w - T[v]);\n                moves.push_back({after - before, 0, i, v, -1});\n            }\n        }\n\n        sort(moves.begin(), moves.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& mv : moves) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> nb = cur.b;\n            nb[mv.i] = mv.v;\n            SimResult sr = simulate_graph(cur.a, nb);\n            Candidate cand = cur;\n            cand.b = move(nb);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- local graph repair: b-swaps ----------\nCandidate local_search_b_swaps(Candidate cur, int rounds = 2, int exactTop = 12) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useB(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useB[i] = dep[i] / 2;\n        }\n\n        vector<MoveCand> ops;\n        ops.reserve(N * N / 2);\n\n        for (int i = 0; i < N; ++i) {\n            if (useB[i] == 0) continue;\n            for (int k = i + 1; k < N; ++k) {\n                if (useB[k] == 0) continue;\n                int u = cur.b[i], v = cur.b[k];\n                if (u == v) continue;\n                int wi = useB[i], wk = useB[k];\n\n                ll before = absll((ll)cur.cnt[u] - T[u]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[u] - wi + wk - T[u]) + absll((ll)cur.cnt[v] - wk + wi - T[v]);\n                ops.push_back({after - before, 2, i, -1, k});\n            }\n        }\n\n        sort(ops.begin(), ops.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.k < b.k;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& op : ops) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> nb = cur.b;\n            swap(nb[op.i], nb[op.k]);\n            SimResult sr = simulate_graph(cur.a, nb);\n            Candidate cand = cur;\n            cand.b = move(nb);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n\n    return best;\n}\n\n// ---------- cautious final repair: small a-moves ----------\nCandidate local_search_small_a_moves(Candidate cur, int rounds = 2, int exactTop = 10) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useA(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useA[i] = (dep[i] + 1) / 2;\n        }\n\n        vector<int> deficit_ids(N);\n        iota(deficit_ids.begin(), deficit_ids.end(), 0);\n        sort(deficit_ids.begin(), deficit_ids.end(), [&](int a, int b) {\n            ll ra = (ll)T[a] - cur.cnt[a];\n            ll rb = (ll)T[b] - cur.cnt[b];\n            if (ra != rb) return ra > rb;\n            return a < b;\n        });\n\n        vector<int> small_src(N);\n        iota(small_src.begin(), small_src.end(), 0);\n        sort(small_src.begin(), small_src.end(), [&](int a, int b) {\n            if (useA[a] != useA[b]) return useA[a] < useA[b];\n            return a < b;\n        });\n\n        vector<int> tgt;\n        for (int k = 0; k < 8; ++k) tgt.push_back(deficit_ids[k]);\n        tgt.push_back(0);\n        sort(tgt.begin(), tgt.end());\n        tgt.erase(unique(tgt.begin(), tgt.end()), tgt.end());\n\n        vector<MoveCand> moves;\n        int src_take = 0;\n        for (int i : small_src) {\n            if (i == 0) continue;\n            int w = useA[i];\n            if (w == 0) continue;\n            ++src_take;\n            if (src_take > 24) break;\n            int old = cur.a[i];\n            for (int v : tgt) {\n                if (v == old) continue;\n                ll before = absll((ll)cur.cnt[old] - T[old]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[old] - w - T[old]) + absll((ll)cur.cnt[v] + w - T[v]);\n                moves.push_back({after - before, 1, i, v, -1});\n            }\n        }\n\n        sort(moves.begin(), moves.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& mv : moves) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> na = cur.a;\n            na[mv.i] = mv.v;\n            SimResult sr = simulate_graph(na, cur.b);\n            Candidate cand = cur;\n            cand.a = move(na);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- systematic local order search ----------\nvector<int> relocate_order(const vector<int>& ord, int i, int j) {\n    vector<int> res = ord;\n    int v = res[i];\n    res.erase(res.begin() + i);\n    if (j > i) --j;\n    res.insert(res.begin() + j, v);\n    return res;\n}\n\nCandidate systematic_order_relocate_search(Candidate start, int rounds = 3, int exactTop = 8) {\n    Candidate best = start;\n    Candidate cur = start;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<pair<ll, pair<int,int>>> cand_moves;\n        cand_moves.reserve((N - 1) * (N - 2));\n\n        for (int i = 1; i < N; ++i) {\n            for (int j = 1; j < N; ++j) {\n                if (i == j) continue;\n                vector<int> ord2 = relocate_order(cur.order, i, j);\n                ll fc = order_cost_fast(ord2, cur.cnt);\n                cand_moves.push_back({fc, {i, j}});\n            }\n        }\n\n        sort(cand_moves.begin(), cand_moves.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        Candidate best_local = cur;\n        set<vector<int>> used_orders;\n        used_orders.insert(cur.order);\n\n        int tried = 0;\n        for (auto &ent : cand_moves) {\n            if (tried >= exactTop) break;\n            int i = ent.second.first;\n            int j = ent.second.second;\n            vector<int> ord2 = relocate_order(cur.order, i, j);\n            if (!used_orders.insert(ord2).second) continue;\n            ++tried;\n            Candidate cand = evaluate_order(ord2, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, best_local)) best_local = move(cand);\n        }\n\n        if (betterCand(best_local, cur)) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> Lw;\n    T.resize(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    mt19937 rng(123456789);\n\n    vector<vector<int>> seeds;\n    {\n        vector<int> desc = sorted_order(true);\n        vector<int> asc = sorted_order(false);\n\n        vector<int> orig(N), revorig(N);\n        iota(orig.begin(), orig.end(), 0);\n        revorig = orig;\n        reverse(revorig.begin(), revorig.end());\n\n        int imin = min_element(T.begin(), T.end()) - T.begin();\n        int imax = max_element(T.begin(), T.end()) - T.begin();\n\n        seeds.push_back(desc);\n        seeds.push_back(asc);\n        seeds.push_back(normalize_order(orig));\n        seeds.push_back(normalize_order(revorig));\n        seeds.push_back(nearest_neighbor_order(0, false));\n        seeds.push_back(nearest_neighbor_order(0, true));\n        seeds.push_back(nearest_neighbor_order(imin, false));\n        seeds.push_back(nearest_neighbor_order(imax, false));\n        seeds.push_back(nearest_neighbor_order(imax, true));\n        seeds.push_back(median_out_order(desc));\n        {\n            auto tmp = median_out_order(desc);\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n        seeds.push_back(alternating_low_high_order());\n        {\n            auto tmp = alternating_low_high_order();\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n    }\n\n    vector<vector<int>> orders;\n    set<vector<int>> seen;\n    for (auto s : seeds) add_order_if_new(orders, seen, s);\n    for (auto s : seeds) {\n        auto opt = optimize_order_fast(s, T, rng, 1200, 3000.0);\n        add_order_if_new(orders, seen, opt);\n    }\n    for (int rep = 0; rep < 10; ++rep) {\n        auto tmp = seeds[rng() % seeds.size()];\n        int mv = 3 + (rng() % 4);\n        for (int k = 0; k < mv; ++k) tmp = mutate_order_random(tmp, rng);\n        tmp = optimize_order_fast(tmp, T, rng, 900, 2200.0);\n        add_order_if_new(orders, seen, tmp);\n    }\n\n    vector<pair<ll, int>> rank_idx;\n    for (int i = 0; i < (int)orders.size(); ++i) {\n        rank_idx.push_back({order_cost_fast(orders[i], T), i});\n    }\n    sort(rank_idx.begin(), rank_idx.end());\n\n    int M = min<int>(20, rank_idx.size());\n    vector<Candidate> cand_list;\n    cand_list.reserve(M);\n\n    for (int z = 0; z < M; ++z) {\n        int idx = rank_idx[z].second;\n        cand_list.push_back(evaluate_order(orders[idx], T, false, -1, 2));\n    }\n\n    sort(cand_list.begin(), cand_list.end(), [&](const Candidate& x, const Candidate& y) {\n        return betterCand(x, y);\n    });\n\n    Candidate best = cand_list[0];\n\n    int topK = min<int>(3, cand_list.size());\n    for (int i = 0; i < topK; ++i) {\n        Candidate improved = improve_candidate_order(cand_list[i], rng);\n        if (betterCand(improved, best)) best = improved;\n    }\n\n    {\n        Candidate fin = evaluate_order(best.order, best.cnt, true, best.end_node, 2);\n        if (betterCand(fin, best)) best = fin;\n    }\n\n    // systematic local order search around the best basin\n    {\n        Candidate c = systematic_order_relocate_search(best, 3, 8);\n        if (betterCand(c, best)) best = c;\n    }\n\n    {\n        Candidate c = refine_endnode_candidate(best);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_b_moves(best, 4, 16);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_b_swaps(best, 2, 12);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = evaluate_order(best.order, best.cnt, true, best.end_node, 1);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_small_a_moves(best, 2, 10);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_b_moves(best, 2, 10);\n        if (betterCand(c, best)) best = c;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << best.a[i] << ' ' << best.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 800;\nstatic constexpr double INF = 1e100;\n\nint N, M, Q, L, Wv;\nvector<int> G;\n\nint LX[MAXN], RX[MAXN], LY[MAXN], RY[MAXN];\nint SX[MAXN], SY[MAXN];          // doubled centers\nint WX[MAXN], WY[MAXN];          // widths\nuint64_t MKEY[MAXN];\ndouble estD[MAXN][MAXN];\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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), 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 GroupItem {\n    int size;\n    int id;\n};\n\nstruct QueryPlan {\n    int gid;\n    vector<int> subset;\n};\n\nstatic inline long long edgeKey(int u, int v) {\n    if (u > v) swap(u, v);\n    return (static_cast<long long>(u) << 11) | v;\n}\n\nuint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nuint64_t mortonEncode(uint32_t x, uint32_t y) {\n    return (uint64_t)part1by1(x) | ((uint64_t)part1by1(y) << 1);\n}\n\nbool cmpMortonCity(int a, int b) {\n    if (MKEY[a] != MKEY[b]) return MKEY[a] < MKEY[b];\n    return a < b;\n}\nbool cmpXCity(int a, int b) {\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    return a < b;\n}\nbool cmpYCity(int a, int b) {\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\n\nvector<int> sort_morton(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpMortonCity);\n    return v;\n}\nvector<int> sort_x(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpXCity);\n    return v;\n}\nvector<int> sort_y(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpYCity);\n    return v;\n}\n\nvector<int> nn_order(const vector<int>& group, int startCity) {\n    int g = (int)group.size();\n    vector<char> used(N, 0);\n    vector<int> ord;\n    ord.reserve(g);\n    int cur = startCity;\n    used[cur] = 1;\n    ord.push_back(cur);\n\n    for (int step = 1; step < g; step++) {\n        int best = -1;\n        double bestD = INF;\n        for (int v : group) {\n            if (used[v]) continue;\n            double d = estD[cur][v];\n            if (best == -1 || d < bestD - 1e-12 ||\n                (fabs(d - bestD) <= 1e-12 && cmpMortonCity(v, best))) {\n                best = v;\n                bestD = d;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return ord;\n}\n\ndouble mst_cost_slice(const vector<int>& ord, int st, int len) {\n    if (len <= 1) return 0.0;\n    double md[16];\n    bool used[16];\n    for (int i = 0; i < len; i++) {\n        md[i] = INF;\n        used[i] = false;\n    }\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < len; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < len; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = true;\n        total += bv;\n        int u = ord[st + bi];\n        for (int j = 0; j < len; j++) {\n            if (!used[j]) {\n                double w = estD[u][ord[st + j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\n// Used to rank query orders.\ndouble chain_cover_cost(const vector<int>& ord) {\n    int g = (int)ord.size();\n    if (g <= 1) return 0.0;\n    if (g == 2) return estD[ord[0]][ord[1]];\n    if (g <= L) return mst_cost_slice(ord, 0, g);\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = estD[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<double> dp(remain + 1, INF), ndp(remain + 1, INF);\n    dp[0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        fill(ndp.begin(), ndp.end(), INF);\n        for (int p = 0; p <= remain; p++) {\n            if (dp[p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[p] + wcost[p][t];\n                if (cand < ndp[np]) ndp[np] = cand;\n            }\n        }\n        dp.swap(ndp);\n    }\n    return dp[remain];\n}\n\ndouble complete_mst_cost(const vector<int>& group) {\n    int g = (int)group.size();\n    if (g <= 1) return 0.0;\n    vector<double> md(g, INF);\n    vector<char> used(g, 0);\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < g; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < g; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = 1;\n        total += bv;\n        int u = group[bi];\n        for (int j = 0; j < g; j++) {\n            if (!used[j]) {\n                double w = estD[u][group[j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\npair<double, vector<pair<int,int>>> complete_mst_edges(const vector<int>& group) {\n    int g = (int)group.size();\n    if (g <= 1) return {0.0, {}};\n    vector<double> md(g, INF);\n    vector<int> par(g, -1);\n    vector<char> used(g, 0);\n    md[0] = 0.0;\n    double total = 0.0;\n    vector<pair<int,int>> edges;\n    edges.reserve(g - 1);\n\n    for (int it = 0; it < g; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < g; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = 1;\n        total += bv;\n        if (par[bi] != -1) {\n            int a = group[bi], b = group[par[bi]];\n            if (a > b) swap(a, b);\n            edges.push_back({a, b});\n        }\n        int u = group[bi];\n        for (int j = 0; j < g; j++) {\n            if (!used[j]) {\n                double w = estD[u][group[j]];\n                if (w < md[j]) {\n                    md[j] = w;\n                    par[j] = bi;\n                }\n            }\n        }\n    }\n    return {total, edges};\n}\n\ndouble span_cost_bbox(int dx, int dy, int cnt, int mode) {\n    double base = (mode == 0) ? (double)(dx + dy) : sqrt((double)dx * dx + (double)dy * dy);\n    return base * sqrt((double)cnt);\n}\n\nvoid kd_rec(const vector<int>& pts, const vector<GroupItem>& items,\n            vector<vector<int>>& ans, int mode) {\n    if ((int)items.size() == 1) {\n        ans[items[0].id] = pts;\n        return;\n    }\n\n    int n = (int)pts.size();\n    int m = (int)items.size();\n\n    vector<vector<char>> poss(m + 1, vector<char>(n + 1, 0));\n    poss[0][0] = 1;\n    for (int i = 0; i < m; i++) {\n        int sz = items[i].size;\n        for (int s = 0; s <= n; s++) {\n            if (!poss[i][s]) continue;\n            poss[i + 1][s] = 1;\n            if (s + sz <= n) poss[i + 1][s + sz] = 1;\n        }\n    }\n\n    vector<int> ordx = pts, ordy = pts;\n    sort(ordx.begin(), ordx.end(), cmpXCity);\n    sort(ordy.begin(), ordy.end(), cmpYCity);\n\n    vector<int> pxMinY(n), pxMaxY(n), sxMinY(n), sxMaxY(n);\n    vector<int> pyMinX(n), pyMaxX(n), syMinX(n), syMaxX(n);\n\n    for (int i = 0; i < n; i++) {\n        int v = ordx[i];\n        if (i == 0) pxMinY[i] = pxMaxY[i] = SY[v];\n        else {\n            pxMinY[i] = min(pxMinY[i - 1], SY[v]);\n            pxMaxY[i] = max(pxMaxY[i - 1], SY[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordx[i];\n        if (i == n - 1) sxMinY[i] = sxMaxY[i] = SY[v];\n        else {\n            sxMinY[i] = min(sxMinY[i + 1], SY[v]);\n            sxMaxY[i] = max(sxMaxY[i + 1], SY[v]);\n        }\n    }\n\n    for (int i = 0; i < n; i++) {\n        int v = ordy[i];\n        if (i == 0) pyMinX[i] = pyMaxX[i] = SX[v];\n        else {\n            pyMinX[i] = min(pyMinX[i - 1], SX[v]);\n            pyMaxX[i] = max(pyMaxX[i - 1], SX[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordy[i];\n        if (i == n - 1) syMinX[i] = syMaxX[i] = SX[v];\n        else {\n            syMinX[i] = min(syMinX[i + 1], SX[v]);\n            syMaxX[i] = max(syMaxX[i + 1], SX[v]);\n        }\n    }\n\n    vector<double> pxSX(n + 1, 0), pxSY(n + 1, 0), pxSXX(n + 1, 0), pxSYY(n + 1, 0);\n    vector<double> pySX(n + 1, 0), pySY(n + 1, 0), pySXX(n + 1, 0), pySYY(n + 1, 0);\n    for (int i = 0; i < n; i++) {\n        int vx = ordx[i], vy = ordy[i];\n        pxSX[i + 1] = pxSX[i] + SX[vx];\n        pxSY[i + 1] = pxSY[i] + SY[vx];\n        pxSXX[i + 1] = pxSXX[i] + 1.0 * SX[vx] * SX[vx];\n        pxSYY[i + 1] = pxSYY[i] + 1.0 * SY[vx] * SY[vx];\n\n        pySX[i + 1] = pySX[i] + SX[vy];\n        pySY[i + 1] = pySY[i] + SY[vy];\n        pySXX[i + 1] = pySXX[i] + 1.0 * SX[vy] * SX[vy];\n        pySYY[i + 1] = pySYY[i] + 1.0 * SY[vy] * SY[vy];\n    }\n\n    auto sse_cost = [&](const vector<double>& SXs, const vector<double>& SYs,\n                        const vector<double>& SXXs, const vector<double>& SYYs,\n                        int l, int r) -> double {\n        int cnt = r - l;\n        if (cnt <= 1) return 0.0;\n        double sumx = SXs[r] - SXs[l];\n        double sumy = SYs[r] - SYs[l];\n        double sumxx = SXXs[r] - SXXs[l];\n        double sumyy = SYYs[r] - SYYs[l];\n        return (sumxx - sumx * sumx / cnt) + (sumyy - sumy * sumy / cnt);\n    };\n\n    double bestScore = INF;\n    int bestS = -1;\n    int bestAxis = 0;\n\n    for (int s = 1; s < n; s++) {\n        if (!poss[m][s]) continue;\n\n        double scoreX, scoreY;\n        if (mode <= 1) {\n            int ldx = SX[ordx[s - 1]] - SX[ordx[0]];\n            int ldy = pxMaxY[s - 1] - pxMinY[s - 1];\n            int rdx = SX[ordx[n - 1]] - SX[ordx[s]];\n            int rdy = sxMaxY[s] - sxMinY[s];\n            scoreX = span_cost_bbox(ldx, ldy, s, mode) + span_cost_bbox(rdx, rdy, n - s, mode);\n\n            int ldy2 = SY[ordy[s - 1]] - SY[ordy[0]];\n            int ldx2 = pyMaxX[s - 1] - pyMinX[s - 1];\n            int rdy2 = SY[ordy[n - 1]] - SY[ordy[s]];\n            int rdx2 = syMaxX[s] - syMinX[s];\n            scoreY = span_cost_bbox(ldx2, ldy2, s, mode) + span_cost_bbox(rdx2, rdy2, n - s, mode);\n        } else {\n            scoreX = sse_cost(pxSX, pxSY, pxSXX, pxSYY, 0, s) +\n                     sse_cost(pxSX, pxSY, pxSXX, pxSYY, s, n);\n            scoreY = sse_cost(pySX, pySY, pySXX, pySYY, 0, s) +\n                     sse_cost(pySX, pySY, pySXX, pySYY, s, n);\n        }\n\n        if (scoreX < bestScore - 1e-9 ||\n            (fabs(scoreX - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n            bestScore = scoreX;\n            bestS = s;\n            bestAxis = 0;\n        }\n        if (scoreY < bestScore - 1e-9 ||\n            (fabs(scoreY - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n            bestScore = scoreY;\n            bestS = s;\n            bestAxis = 1;\n        }\n    }\n\n    if (bestS == -1) {\n        bestS = n / 2;\n        bestAxis = 0;\n    }\n\n    vector<GroupItem> leftItems, rightItems;\n    int sum = bestS;\n    for (int i = m - 1; i >= 0; i--) {\n        int sz = items[i].size;\n        if (sum >= sz && poss[i][sum - sz]) {\n            leftItems.push_back(items[i]);\n            sum -= sz;\n        } else {\n            rightItems.push_back(items[i]);\n        }\n    }\n    reverse(leftItems.begin(), leftItems.end());\n    reverse(rightItems.begin(), rightItems.end());\n\n    const vector<int>& ord = (bestAxis == 0 ? ordx : ordy);\n    vector<int> leftPts(ord.begin(), ord.begin() + bestS);\n    vector<int> rightPts(ord.begin() + bestS, ord.end());\n\n    kd_rec(leftPts, leftItems, ans, mode);\n    kd_rec(rightPts, rightItems, ans, mode);\n}\n\nvector<vector<int>> makeKD(int mode, const vector<int>& itemOrder) {\n    vector<vector<int>> ans(M);\n    vector<int> pts(N);\n    iota(pts.begin(), pts.end(), 0);\n    vector<GroupItem> items;\n    items.reserve(M);\n    for (int gid : itemOrder) items.push_back({G[gid], gid});\n    kd_rec(pts, items, ans, mode);\n    return ans;\n}\n\nvector<vector<int>> makeContiguous(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n    vector<vector<int>> groups(M);\n    int pos = 0;\n    for (int gid : groupOrder) {\n        groups[gid] = vector<int>(cityOrder.begin() + pos, cityOrder.begin() + pos + G[gid]);\n        pos += G[gid];\n    }\n    return groups;\n}\n\ndouble eval_grouping(const vector<vector<int>>& groups) {\n    double sc = 0.0;\n    for (int gid = 0; gid < M; gid++) sc += complete_mst_cost(groups[gid]);\n    return sc;\n}\n\nvector<pair<int,int>> ask(const vector<int>& sub) {\n    cout << \"? \" << sub.size();\n    for (int v : sub) cout << ' ' << v;\n    cout << '\\n';\n    cout.flush();\n\n    vector<pair<int,int>> ret;\n    ret.reserve((int)sub.size() - 1);\n    for (int i = 0; i < (int)sub.size() - 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.push_back({a, b});\n    }\n    return ret;\n}\n\nstruct GroupOrderPack {\n    vector<vector<int>> ranked;\n};\n\nGroupOrderPack make_group_orders(const vector<int>& group) {\n    GroupOrderPack pack;\n    int g = (int)group.size();\n    if (g <= 2) {\n        pack.ranked.push_back(group);\n        return pack;\n    }\n\n    vector<vector<int>> cand;\n    auto add_ord = [&](const vector<int>& ord) {\n        for (const auto& ex : cand) if (ex == ord) return;\n        cand.push_back(ord);\n    };\n\n    auto mort = sort_morton(group);\n    auto xord = sort_x(group);\n    auto yord = sort_y(group);\n\n    add_ord(mort);\n    {\n        auto t = mort;\n        reverse(t.begin(), t.end());\n        add_ord(t);\n    }\n    add_ord(xord);\n    {\n        auto t = xord;\n        reverse(t.begin(), t.end());\n        add_ord(t);\n    }\n    add_ord(yord);\n    {\n        auto t = yord;\n        reverse(t.begin(), t.end());\n        add_ord(t);\n    }\n\n    int leftmost = *min_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n    int rightmost = *max_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n\n    {\n        auto nnL = nn_order(group, leftmost);\n        add_ord(nnL);\n        auto rev = nnL;\n        reverse(rev.begin(), rev.end());\n        add_ord(rev);\n    }\n    if (rightmost != leftmost) {\n        auto nnR = nn_order(group, rightmost);\n        add_ord(nnR);\n        auto rev = nnR;\n        reverse(rev.begin(), rev.end());\n        add_ord(rev);\n    }\n\n    vector<pair<double,int>> scored;\n    scored.reserve((int)cand.size());\n    for (int i = 0; i < (int)cand.size(); i++) {\n        scored.push_back({chain_cover_cost(cand[i]), i});\n    }\n    sort(scored.begin(), scored.end());\n\n    for (auto [c, idx] : scored) pack.ranked.push_back(cand[idx]);\n    return pack;\n}\n\nvector<vector<int>> gen_cover_windows(const vector<int>& ord) {\n    int g = (int)ord.size();\n    vector<vector<int>> res;\n    if (g <= L) {\n        res.push_back(ord);\n        return res;\n    }\n    vector<int> starts;\n    for (int s = 0; s + L < g; s += (L - 1)) starts.push_back(s);\n    if (starts.empty() || starts.back() != g - L) starts.push_back(g - L);\n    for (int s : starts) {\n        res.emplace_back(ord.begin() + s, ord.begin() + s + L);\n    }\n    return res;\n}\n\nvector<vector<int>> gen_regular_windows(const vector<int>& ord, int offset) {\n    int g = (int)ord.size();\n    vector<vector<int>> res;\n    if (g <= L) return res;\n    if (offset < 0 || offset >= (L - 1)) return res;\n    for (int s = offset; s + L <= g; s += (L - 1)) {\n        res.emplace_back(ord.begin() + s, ord.begin() + s + L);\n    }\n    return res;\n}\n\ndouble centroid_proxy_cost(int city, int gid,\n                           const vector<long long>& sumX,\n                           const vector<long long>& sumY,\n                           const vector<int>& gsz) {\n    double cx = (double)sumX[gid] / gsz[gid];\n    double cy = (double)sumY[gid] / gsz[gid];\n    double dx = SX[city] - cx;\n    double dy = SY[city] - cy;\n    return dx * dx + dy * dy;\n}\n\nvoid improve_grouping_swaps(vector<vector<int>>& groups,\n                            const vector<int>& cityMort,\n                            const vector<int>& cityX,\n                            const vector<int>& cityY) {\n    vector<int> cityGroup(N), posInGroup(N), gsz(M);\n    vector<long long> sumX(M, 0), sumY(M, 0);\n    vector<double> gcost(M, 0.0);\n\n    int maxG = 0;\n    for (int gid = 0; gid < M; gid++) {\n        gsz[gid] = (int)groups[gid].size();\n        maxG = max(maxG, gsz[gid]);\n        for (int i = 0; i < gsz[gid]; i++) {\n            int v = groups[gid][i];\n            cityGroup[v] = gid;\n            posInGroup[v] = i;\n            sumX[gid] += SX[v];\n            sumY[gid] += SY[v];\n        }\n        gcost[gid] = complete_mst_cost(groups[gid]);\n    }\n\n    vector<pair<double, pair<int,int>>> candPairs;\n    candPairs.reserve(30000);\n    unordered_set<long long> seen;\n    seen.reserve(40000);\n\n    auto add_by_order = [&](const vector<int>& ord, int rad) {\n        int n = (int)ord.size();\n        for (int i = 0; i < n; i++) {\n            for (int d = 1; d <= rad; d++) {\n                if (i + d >= n) break;\n                int u = ord[i], v = ord[i + d];\n                long long key = edgeKey(u, v);\n                if (seen.insert(key).second) {\n                    candPairs.push_back({estD[u][v], {u, v}});\n                }\n            }\n        }\n    };\n\n    add_by_order(cityMort, 6);\n    add_by_order(cityX, 4);\n    add_by_order(cityY, 4);\n\n    sort(candPairs.begin(), candPairs.end(),\n         [&](const auto& a, const auto& b) {\n             if (fabs(a.first - b.first) > 1e-12) return a.first < b.first;\n             if (a.second.first != b.second.first) return a.second.first < b.second.first;\n             return a.second.second < b.second.second;\n         });\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n    };\n\n    double budgetMs = 300.0;\n    if (maxG >= 200) budgetMs = 220.0;\n    else if (maxG >= 120) budgetMs = 260.0;\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (auto& cp : candPairs) {\n            if (elapsed_ms() > budgetMs) return;\n\n            int u = cp.second.first;\n            int v = cp.second.second;\n            int gu = cityGroup[u];\n            int gv = cityGroup[v];\n            if (gu == gv) continue;\n\n            int sa = gsz[gu];\n            int sb = gsz[gv];\n\n            double oldP = centroid_proxy_cost(u, gu, sumX, sumY, gsz)\n                        + centroid_proxy_cost(v, gv, sumX, sumY, gsz);\n            double newP = centroid_proxy_cost(v, gu, sumX, sumY, gsz)\n                        + centroid_proxy_cost(u, gv, sumX, sumY, gsz);\n\n            bool small = (sa + sb <= 20 || sa <= 8 || sb <= 8);\n            long long weight = 1LL * sa * sa + 1LL * sb * sb;\n\n            if (!small && newP >= oldP * 0.985) continue;\n            if (weight > 20000 && newP >= oldP * 0.93) continue;\n            if (weight > 80000 && newP >= oldP * 0.82) continue;\n\n            int pu = posInGroup[u];\n            int pv = posInGroup[v];\n\n            vector<int> A2 = groups[gu];\n            vector<int> B2 = groups[gv];\n            A2[pu] = v;\n            B2[pv] = u;\n\n            double newA = complete_mst_cost(A2);\n            double newB = complete_mst_cost(B2);\n\n            if (newA + newB + 1e-9 < gcost[gu] + gcost[gv]) {\n                groups[gu][pu] = v;\n                groups[gv][pv] = u;\n\n                cityGroup[v] = gu;\n                posInGroup[v] = pu;\n                cityGroup[u] = gv;\n                posInGroup[u] = pv;\n\n                sumX[gu] += SX[v] - SX[u];\n                sumY[gu] += SY[v] - SY[u];\n                sumX[gv] += SX[u] - SX[v];\n                sumY[gv] += SY[u] - SY[v];\n\n                gcost[gu] = newA;\n                gcost[gv] = newB;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> Q >> L >> Wv;\n    G.resize(M);\n    for (int i = 0; i < M; i++) cin >> G[i];\n\n    for (int i = 0; i < N; i++) {\n        cin >> LX[i] >> RX[i] >> LY[i] >> RY[i];\n        SX[i] = LX[i] + RX[i];\n        SY[i] = LY[i] + RY[i];\n        WX[i] = RX[i] - LX[i];\n        WY[i] = RY[i] - LY[i];\n        MKEY[i] = mortonEncode((uint32_t)SX[i], (uint32_t)SY[i]);\n    }\n\n    vector<double> varTerm(N);\n    for (int i = 0; i < N; i++) {\n        varTerm[i] = (1.0 * WX[i] * WX[i] + 1.0 * WY[i] * WY[i]) / 12.0;\n    }\n    for (int i = 0; i < N; i++) {\n        estD[i][i] = 0.0;\n        for (int j = i + 1; j < N; j++) {\n            double dx = (SX[i] - SX[j]) * 0.5;\n            double dy = (SY[i] - SY[j]) * 0.5;\n            double d2 = dx * dx + dy * dy + varTerm[i] + varTerm[j];\n            estD[i][j] = estD[j][i] = sqrt(max(0.0, d2));\n        }\n    }\n\n    vector<int> allCities(N);\n    iota(allCities.begin(), allCities.end(), 0);\n\n    vector<int> cityMort = allCities, cityX = allCities, cityY = allCities, cityMortRev;\n    sort(cityMort.begin(), cityMort.end(), cmpMortonCity);\n    sort(cityX.begin(), cityX.end(), cmpXCity);\n    sort(cityY.begin(), cityY.end(), cmpYCity);\n    cityMortRev = cityMort;\n    reverse(cityMortRev.begin(), cityMortRev.end());\n\n    vector<int> groupAsc(M), groupDesc(M), groupOrig(M), groupRnd(M);\n    iota(groupAsc.begin(), groupAsc.end(), 0);\n    iota(groupDesc.begin(), groupDesc.end(), 0);\n    iota(groupOrig.begin(), groupOrig.end(), 0);\n    iota(groupRnd.begin(), groupRnd.end(), 0);\n\n    sort(groupAsc.begin(), groupAsc.end(), [&](int a, int b) {\n        if (G[a] != G[b]) return G[a] < G[b];\n        return a < b;\n    });\n    groupDesc = groupAsc;\n    reverse(groupDesc.begin(), groupDesc.end());\n\n    mt19937 rng(123456789);\n    shuffle(groupRnd.begin(), groupRnd.end(), rng);\n\n    double bestGroupingScore = INF;\n    vector<vector<int>> bestGroups;\n\n    auto try_grouping = [&](vector<vector<int>> cand) {\n        double sc = eval_grouping(cand);\n        if (sc < bestGroupingScore) {\n            bestGroupingScore = sc;\n            bestGroups = move(cand);\n        }\n    };\n\n    for (int mode = 0; mode < 3; mode++) {\n        try_grouping(makeKD(mode, groupAsc));\n        try_grouping(makeKD(mode, groupDesc));\n        try_grouping(makeKD(mode, groupOrig));\n        try_grouping(makeKD(mode, groupRnd));\n    }\n\n    try_grouping(makeContiguous(cityMort, groupAsc));\n    try_grouping(makeContiguous(cityMort, groupDesc));\n    try_grouping(makeContiguous(cityMort, groupOrig));\n    try_grouping(makeContiguous(cityMortRev, groupAsc));\n    try_grouping(makeContiguous(cityMortRev, groupDesc));\n    try_grouping(makeContiguous(cityX, groupAsc));\n    try_grouping(makeContiguous(cityX, groupDesc));\n    try_grouping(makeContiguous(cityX, groupOrig));\n    try_grouping(makeContiguous(cityY, groupAsc));\n    try_grouping(makeContiguous(cityY, groupDesc));\n    try_grouping(makeContiguous(cityY, groupOrig));\n\n    improve_grouping_swaps(bestGroups, cityMort, cityX, cityY);\n\n    vector<GroupOrderPack> orderPacks(M);\n    vector<double> groupEstCost(M, 0.0);\n    vector<vector<pair<int,int>>> estMSTEdges(M);\n    vector<vector<int>> outputCityOrder(M);\n\n    for (int gid = 0; gid < M; gid++) {\n        groupEstCost[gid] = complete_mst_cost(bestGroups[gid]);\n        auto mstInfo = complete_mst_edges(bestGroups[gid]);\n        estMSTEdges[gid] = move(mstInfo.second);\n\n        orderPacks[gid] = make_group_orders(bestGroups[gid]);\n        if (!orderPacks[gid].ranked.empty()) outputCityOrder[gid] = orderPacks[gid].ranked[0];\n        else outputCityOrder[gid] = bestGroups[gid];\n    }\n\n    vector<int> priorityGroups(M);\n    iota(priorityGroups.begin(), priorityGroups.end(), 0);\n    sort(priorityGroups.begin(), priorityGroups.end(), [&](int a, int b) {\n        if (groupEstCost[a] != groupEstCost[b]) return groupEstCost[a] > groupEstCost[b];\n        return G[a] > G[b];\n    });\n\n    vector<set<vector<int>>> seenSubsets(M);\n    vector<QueryPlan> plans;\n    plans.reserve(Q);\n\n    auto try_add_plan = [&](int gid, const vector<int>& sub) {\n        if ((int)plans.size() >= Q) return;\n        if ((int)sub.size() < 2 || (int)sub.size() > L) return;\n        vector<int> key = sub;\n        sort(key.begin(), key.end());\n        if (seenSubsets[gid].insert(key).second) {\n            plans.push_back({gid, sub});\n        }\n    };\n\n    for (int gid = 0; gid < M; gid++) {\n        int g = G[gid];\n        if (g <= 1) continue;\n        if (g == 2) continue;\n        if (g <= L) {\n            try_add_plan(gid, outputCityOrder[gid]);\n        } else {\n            for (auto& sub : gen_cover_windows(outputCityOrder[gid])) {\n                try_add_plan(gid, sub);\n            }\n        }\n    }\n\n    int midOffset = (L - 1) / 2;\n\n    auto add_round = [&](int ordIdx, int offset, bool coverStyle) {\n        for (int gid : priorityGroups) {\n            if ((int)plans.size() >= Q) return;\n            int g = G[gid];\n            if (g <= L) continue;\n            if ((int)orderPacks[gid].ranked.size() <= ordIdx) continue;\n            const auto& ord = orderPacks[gid].ranked[ordIdx];\n            vector<vector<int>> win;\n            if (coverStyle) win = gen_cover_windows(ord);\n            else win = gen_regular_windows(ord, offset);\n            for (auto& sub : win) {\n                if ((int)plans.size() >= Q) return;\n                try_add_plan(gid, sub);\n            }\n        }\n    };\n\n    add_round(1, 0, false);\n    if (midOffset > 0) add_round(0, midOffset, false);\n    if (midOffset > 0) add_round(1, midOffset, false);\n    add_round(2, 0, false);\n\n    vector<unordered_map<long long,int>> queryEdgeCount(M);\n    vector<vector<pair<int,int>>> exactSmallGroupEdges(M);\n\n    for (auto& qp : plans) {\n        auto ret = ask(qp.subset);\n        for (auto [a, b] : ret) {\n            queryEdgeCount[qp.gid][edgeKey(a, b)]++;\n        }\n        if (G[qp.gid] >= 3 && G[qp.gid] <= L) {\n            if ((int)qp.subset.size() == G[qp.gid]) {\n                exactSmallGroupEdges[qp.gid] = ret;\n            }\n        }\n    }\n\n    vector<vector<pair<int,int>>> answerEdges(M);\n\n    for (int gid = 0; gid < M; gid++) {\n        int g = G[gid];\n        const auto& group = bestGroups[gid];\n        answerEdges[gid].clear();\n\n        if (g <= 1) continue;\n\n        if (g == 2) {\n            int a = group[0], b = group[1];\n            if (a > b) swap(a, b);\n            answerEdges[gid].push_back({a, b});\n            continue;\n        }\n\n        if (g <= L && !exactSmallGroupEdges[gid].empty()) {\n            answerEdges[gid] = exactSmallGroupEdges[gid];\n            sort(answerEdges[gid].begin(), answerEdges[gid].end());\n            continue;\n        }\n\n        unordered_map<long long,int> qcnt = queryEdgeCount[gid];\n        unordered_set<long long> edgeSeen;\n\n        struct EItem {\n            double w;\n            int u, v;\n        };\n        vector<EItem> cand;\n        cand.reserve(g * 24);\n\n        auto addCand = [&](int u, int v) {\n            if (u == v) return;\n            if (u > v) swap(u, v);\n            long long key = edgeKey(u, v);\n            if (!edgeSeen.insert(key).second) return;\n            int cnt = 0;\n            auto it = qcnt.find(key);\n            if (it != qcnt.end()) cnt = it->second;\n            double factor = 1.0 / (1.0 + 0.12 * min(cnt, 4));\n            cand.push_back({estD[u][v] * factor, u, v});\n        };\n\n        for (auto& kv : qcnt) {\n            int u = (int)(kv.first >> 11);\n            int v = (int)(kv.first & ((1 << 11) - 1));\n            addCand(u, v);\n        }\n\n        for (auto [a, b] : estMSTEdges[gid]) addCand(a, b);\n\n        vector<vector<int>> useOrders;\n        for (int t = 0; t < min(4, (int)orderPacks[gid].ranked.size()); t++) {\n            useOrders.push_back(orderPacks[gid].ranked[t]);\n        }\n        {\n            auto mort = sort_morton(group);\n            bool dup = false;\n            for (auto& v : useOrders) if (v == mort) dup = true;\n            if (!dup) useOrders.push_back(mort);\n        }\n        {\n            auto xord = sort_x(group);\n            bool dup = false;\n            for (auto& v : useOrders) if (v == xord) dup = true;\n            if (!dup) useOrders.push_back(xord);\n        }\n        {\n            auto yord = sort_y(group);\n            bool dup = false;\n            for (auto& v : useOrders) if (v == yord) dup = true;\n            if (!dup) useOrders.push_back(yord);\n        }\n\n        for (auto& ord : useOrders) {\n            int gg = (int)ord.size();\n            for (int i = 0; i < gg; i++) {\n                for (int d = 1; d <= 2; d++) {\n                    if (i + d < gg) addCand(ord[i], ord[i + d]);\n                }\n            }\n        }\n\n        const int KNN = 4;\n        for (int i = 0; i < g; i++) {\n            int u = group[i];\n            vector<pair<double,int>> tmp;\n            tmp.reserve(g - 1);\n            for (int j = 0; j < g; j++) {\n                if (i == j) continue;\n                int v = group[j];\n                tmp.push_back({estD[u][v], v});\n            }\n            int lim = min(KNN, (int)tmp.size());\n            if ((int)tmp.size() > KNN) {\n                nth_element(tmp.begin(), tmp.begin() + KNN, tmp.end());\n            }\n            for (int t = 0; t < lim; t++) addCand(u, tmp[t].second);\n        }\n\n        sort(cand.begin(), cand.end(), [&](const EItem& a, const EItem& b) {\n            if (fabs(a.w - b.w) > 1e-12) return a.w < b.w;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        DSU dsu(N);\n        vector<pair<int,int>> chosen;\n        chosen.reserve(g - 1);\n\n        for (auto& e : cand) {\n            if (dsu.unite(e.u, e.v)) {\n                chosen.push_back({e.u, e.v});\n                if ((int)chosen.size() == g - 1) break;\n            }\n        }\n\n        if ((int)chosen.size() < g - 1) {\n            auto ord = outputCityOrder[gid];\n            for (int i = 1; i < (int)ord.size(); i++) {\n                int a = ord[i - 1], b = ord[i];\n                if (a > b) swap(a, b);\n                if (dsu.unite(a, b)) chosen.push_back({a, b});\n            }\n        }\n\n        for (auto& e : chosen) {\n            if (e.first > e.second) swap(e.first, e.second);\n        }\n        sort(chosen.begin(), chosen.end());\n        answerEdges[gid] = move(chosen);\n    }\n\n    cout << \"!\" << '\\n';\n    for (int gid = 0; gid < M; gid++) {\n        const auto& ord = outputCityOrder[gid];\n        for (int i = 0; i < (int)ord.size(); i++) {\n            if (i) cout << ' ';\n            cout << ord[i];\n        }\n        cout << '\\n';\n        for (auto [a, b] : answerEdges[gid]) {\n            cout << a << ' ' << b << '\\n';\n        }\n    }\n    cout.flush();\n\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 40;\nstatic constexpr int MAXV = 400;\nstatic constexpr int INF = 1e9;\n\nstruct Point {\n    int r, c;\n};\n\nstruct Cmd {\n    char a, d;\n};\n\nstruct Graph {\n    array<uint8_t, MAXV> cnt{};\n    array<array<uint16_t, 8>, MAXV> to{};\n    array<array<uint8_t, 8>, MAXV> act{};\n\n    array<uint8_t, MAXV> rcnt{};\n    array<array<uint16_t, 48>, MAXV> rev{};\n};\n\nstruct Solver {\n    int N, M, V;\n    array<Point, MAXM> pts{};\n    array<int, MAXM> cells{};\n    array<uint8_t, MAXV> special{};\n\n    vector<int> cand[MAXM];\n\n    mt19937 rng;\n    chrono::steady_clock::time_point st;\n    double TL = 1.92;\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n    const char dirC[4] = {'U', 'D', 'L', 'R'};\n\n    using Assign = array<int, MAXM>;\n\n    // scratch\n    Graph g0, g1;\n    array<short, MAXV> dist0{}, dist1{}, dist2{};\n    array<short, MAXV> prevPos{};\n    array<int8_t, MAXV> prevAct{};\n\n    Solver(int N_, int M_, const vector<Point>& in) : N(N_), M(M_), V(N_ * N_), rng(123456789) {\n        for (int i = 0; i < M; i++) pts[i] = in[i];\n        special.fill(0);\n        for (int i = 0; i < M; i++) {\n            cells[i] = id(pts[i].r, pts[i].c);\n            special[cells[i]] = 1;\n        }\n        build_candidates();\n        st = chrono::steady_clock::now();\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    inline bool time_up(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline int id(int r, int c) const { return r * N + c; }\n    inline int row(int v) const { return v / N; }\n    inline int col(int v) const { return v % N; }\n    inline bool inside(int r, int c) const { return 0 <= r && r < N && 0 <= c && c < N; }\n\n    int adj_dir(int from, int to) const {\n        int fr = row(from), fc = col(from);\n        int tr = row(to), tc = col(to);\n        for (int d = 0; d < 4; d++) {\n            if (fr + dr[d] == tr && fc + dc[d] == tc) return d;\n        }\n        return -1;\n    }\n\n    void build_candidates() {\n        for (int k = 1; k < M; k++) {\n            cand[k].clear();\n            cand[k].push_back(-1);\n            int r = pts[k].r, c = pts[k].c;\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                int v = id(nr, nc);\n                // Keep it simple/safe: do not place on start/targets.\n                if (!special[v]) cand[k].push_back(v);\n            }\n            sort(cand[k].begin(), cand[k].end());\n            cand[k].erase(unique(cand[k].begin(), cand[k].end()), cand[k].end());\n        }\n    }\n\n    void build_graph(const array<uint8_t, MAXV>& blocked, Graph& g) {\n        int slU[MAXV], slD[MAXV], slL[MAXV], slR[MAXV];\n\n        g.cnt.fill(0);\n        g.rcnt.fill(0);\n\n        for (int r = 0; r < N; r++) {\n            int lb = -1;\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                if (blocked[v]) lb = c;\n                else slL[v] = id(r, lb + 1);\n            }\n            int rb = N;\n            for (int c = N - 1; c >= 0; c--) {\n                int v = id(r, c);\n                if (blocked[v]) rb = c;\n                else slR[v] = id(r, rb - 1);\n            }\n        }\n\n        for (int c = 0; c < N; c++) {\n            int ub = -1;\n            for (int r = 0; r < N; r++) {\n                int v = id(r, c);\n                if (blocked[v]) ub = r;\n                else slU[v] = id(ub + 1, c);\n            }\n            int db = N;\n            for (int r = N - 1; r >= 0; r--) {\n                int v = id(r, c);\n                if (blocked[v]) db = r;\n                else slD[v] = id(db - 1, c);\n            }\n        }\n\n        for (int p = 0; p < V; p++) {\n            if (blocked[p]) continue;\n            int r = row(p), c = col(p);\n\n            auto add_edge = [&](int to, int act) {\n                if (to == p) return;\n                auto &cc = g.cnt[p];\n                for (int i = 0; i < cc; i++) {\n                    if (g.to[p][i] == to) return;\n                }\n                g.to[p][cc] = (uint16_t)to;\n                g.act[p][cc] = (uint8_t)act;\n                cc++;\n            };\n\n            add_edge(slU[p], 4);\n            add_edge(slD[p], 5);\n            add_edge(slL[p], 6);\n            add_edge(slR[p], 7);\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                int v = id(nr, nc);\n                if (!blocked[v]) add_edge(v, d);\n            }\n        }\n\n        for (int u = 0; u < V; u++) {\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                g.rev[v][g.rcnt[v]++] = (uint16_t)u;\n            }\n        }\n    }\n\n    void bfs_all(const Graph& g, int src, int forbid, array<short, MAXV>& dist) {\n        dist.fill(-1);\n        if (src == forbid) return;\n        int q[MAXV], qh = 0, qt = 0;\n        dist[src] = 0;\n        q[qt++] = src;\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    void bfs_rev_all(const Graph& g, int dst, int forbid, array<short, MAXV>& dist) {\n        dist.fill(-1);\n        if (dst == forbid) return;\n        int q[MAXV], qh = 0, qt = 0;\n        dist[dst] = 0;\n        q[qt++] = dst;\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.rcnt[u]; i++) {\n                int v = g.rev[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    bool bfs_path(const Graph& g, int src, int dst, int forbid, vector<int>& acts) {\n        acts.clear();\n        if (src == dst) return true;\n\n        dist0.fill(-1);\n        prevPos.fill(-1);\n        prevAct.fill(-1);\n\n        if (src == forbid) return false;\n\n        int q[MAXV], qh = 0, qt = 0;\n        dist0[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist0[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist0[v] != -1) continue;\n                dist0[v] = nd;\n                prevPos[v] = (short)u;\n                prevAct[v] = (int8_t)g.act[u][i];\n                if (v == dst) {\n                    qh = qt;\n                    break;\n                }\n                q[qt++] = v;\n            }\n        }\n\n        if (dist0[dst] == -1) return false;\n\n        int cur = dst;\n        while (cur != src) {\n            acts.push_back(prevAct[cur]);\n            cur = prevPos[cur];\n        }\n        reverse(acts.begin(), acts.end());\n        return true;\n    }\n\n    void append_acts(vector<Cmd>& ans, const vector<int>& acts) const {\n        for (int a : acts) {\n            if (a < 4) ans.push_back({'M', dirC[a]});\n            else ans.push_back({'S', dirC[a - 4]});\n        }\n    }\n\n    Cmd alter_cmd(int from, int block_cell) const {\n        int d = adj_dir(from, block_cell);\n        return {'A', dirC[d]};\n    }\n\n    int segment_best_move_cost(array<uint8_t, MAXV>& blocked, int cur, int target, int x) {\n        build_graph(blocked, g0);\n        bfs_all(g0, cur, -1, dist0);\n\n        int best = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n        if (x != -1 && !blocked[x]) {\n            bfs_all(g0, cur, target, dist1);\n\n            blocked[x] = 1;\n            build_graph(blocked, g1);\n            bfs_rev_all(g1, target, -1, dist2);\n            blocked[x] = 0;\n\n            int pre = INF;\n            int xr = row(x), xc = col(x);\n            for (int d = 0; d < 4; d++) {\n                int vr = xr + dr[d], vc = xc + dc[d];\n                if (!inside(vr, vc)) continue;\n                int v = id(vr, vc);\n                if (v == target) continue;\n                if (blocked[v]) continue;\n                if (dist1[v] == -1 || dist2[v] == -1) continue;\n                pre = min(pre, (int)dist1[v] + (int)dist2[v]);\n            }\n            best = min(best, pre);\n        }\n\n        return best;\n    }\n\n    int eval_assignment(const Assign& asg, int cutoff = INF) {\n        array<uint8_t, MAXV> wanted{}, blocked{};\n        wanted.fill(0);\n        blocked.fill(0);\n\n        int uniq = 0;\n        for (int k = 1; k < M; k++) {\n            int x = asg[k];\n            if (x == -1) continue;\n            if (!wanted[x]) {\n                wanted[x] = 1;\n                uniq++;\n            }\n        }\n\n        int total = uniq;\n        if (total >= cutoff) return total;\n\n        int cur = cells[0];\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            int mv = segment_best_move_cost(blocked, cur, target, x);\n            if (mv >= INF) return INF;\n\n            total += mv;\n            if (total >= cutoff) return total;\n\n            if (x != -1) blocked[x] = 1;\n            cur = target;\n        }\n        return total;\n    }\n\n    Assign all_none_assign() const {\n        Assign a;\n        a.fill(-1);\n        return a;\n    }\n\n    Assign heuristic_prev_assign() const {\n        Assign asg;\n        asg.fill(-1);\n        for (int k = 1; k < M; k++) {\n            int cur = cells[k], prv = cells[k - 1];\n            int r = row(cur), c = col(cur);\n            int pr = row(prv), pc = col(prv);\n\n            vector<int> pref;\n            if (abs(pc - c) <= abs(pr - r)) {\n                if (pr <= r) pref = {1, 0, 3, 2};\n                else         pref = {0, 1, 2, 3};\n            } else {\n                if (pc <= c) pref = {3, 2, 1, 0};\n                else         pref = {2, 3, 0, 1};\n            }\n\n            int chosen = -1;\n            for (int pd : pref) {\n                for (int x : cand[k]) {\n                    if (x == -1) continue;\n                    if (adj_dir(cur, x) == pd) {\n                        chosen = x;\n                        break;\n                    }\n                }\n                if (chosen != -1) break;\n            }\n            asg[k] = chosen;\n        }\n        return asg;\n    }\n\n    Assign greedy_init() {\n        Assign asg;\n        asg.fill(-1);\n\n        array<uint8_t, MAXV> used{}, blocked{};\n        used.fill(0);\n        blocked.fill(0);\n\n        int cur = cells[0];\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int bestx = -1;\n            int bestScore = INF;\n\n            for (int x : cand[k]) {\n                int mv = segment_best_move_cost(blocked, cur, target, x);\n                if (mv >= INF) continue;\n                int extra = (x != -1 && !used[x]) ? 1 : 0;\n                int sc = mv + extra;\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestx = x;\n                }\n            }\n\n            asg[k] = bestx;\n            if (bestx != -1) {\n                used[bestx] = 1;\n                blocked[bestx] = 1;\n            }\n            cur = target;\n        }\n        return asg;\n    }\n\n    Assign random_init() {\n        Assign asg;\n        asg.fill(-1);\n        for (int k = 1; k < M; k++) {\n            if (cand[k].size() == 1) {\n                asg[k] = -1;\n                continue;\n            }\n            int sz = (int)cand[k].size();\n            int pick = (int)(rng() % (sz + 2));\n            if (pick >= sz) asg[k] = -1;\n            else asg[k] = cand[k][pick];\n        }\n        return asg;\n    }\n\n    pair<Assign, int> hill_climb(Assign asg, int curScore) {\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 1);\n\n        int pass = 0;\n        while (!time_up(0.06) && pass < 8) {\n            pass++;\n            shuffle(order.begin(), order.end(), rng);\n\n            bool changed = false;\n            bool strict = false;\n\n            for (int k : order) {\n                if (time_up(0.06)) break;\n\n                int old = asg[k];\n                int bestx = old;\n                int bestScore = curScore;\n\n                for (int x : cand[k]) {\n                    if (x == old) continue;\n                    asg[k] = x;\n                    int sc = eval_assignment(asg, bestScore);\n                    if (sc < bestScore || (sc == bestScore && x != old && (rng() & 7) == 0)) {\n                        bestScore = sc;\n                        bestx = x;\n                    }\n                }\n\n                asg[k] = bestx;\n                if (bestx != old) {\n                    changed = true;\n                    if (bestScore < curScore) strict = true;\n                    curScore = bestScore;\n                }\n            }\n\n            if (!changed) break;\n            if (!strict && pass >= 3) break;\n        }\n\n        return {asg, curScore};\n    }\n\n    vector<Cmd> build_answer(const Assign& asg) {\n        vector<Cmd> ans;\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        int cur = cells[0];\n        vector<int> acts;\n\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            build_graph(blocked, g0);\n            bfs_all(g0, cur, -1, dist0);\n            int direct = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            int pre = INF, bestV = -1;\n\n            if (x != -1 && !blocked[x]) {\n                bfs_all(g0, cur, target, dist1);\n\n                blocked[x] = 1;\n                build_graph(blocked, g1);\n                bfs_rev_all(g1, target, -1, dist2);\n                blocked[x] = 0;\n\n                int xr = row(x), xc = col(x);\n                for (int d = 0; d < 4; d++) {\n                    int vr = xr + dr[d], vc = xc + dc[d];\n                    if (!inside(vr, vc)) continue;\n                    int v = id(vr, vc);\n                    if (v == target) continue;\n                    if (blocked[v]) continue;\n                    if (dist1[v] == -1 || dist2[v] == -1) continue;\n                    int sc = (int)dist1[v] + (int)dist2[v];\n                    if (sc < pre) {\n                        pre = sc;\n                        bestV = v;\n                    }\n                }\n            }\n\n            bool use_pre = (pre < direct);\n\n            if (!use_pre) {\n                if (!bfs_path(g0, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n\n                if (x != -1 && !blocked[x]) {\n                    ans.push_back(alter_cmd(cur, x));\n                    blocked[x] = 1;\n                }\n            } else {\n                if (!bfs_path(g0, cur, bestV, target, acts)) return {};\n                append_acts(ans, acts);\n                cur = bestV;\n\n                ans.push_back(alter_cmd(cur, x));\n                blocked[x] = 1;\n\n                build_graph(blocked, g1);\n                if (!bfs_path(g1, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n            }\n        }\n\n        return ans;\n    }\n\n    pair<bool, int> simulate(const vector<Cmd>& ans) const {\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        int cur = cells[0];\n        int t = 1;\n\n        auto dir_idx = [&](char d) -> int {\n            if (d == 'U') return 0;\n            if (d == 'D') return 1;\n            if (d == 'L') return 2;\n            return 3;\n        };\n\n        for (auto &cmd : ans) {\n            int d = dir_idx(cmd.d);\n            if (cmd.a == 'M') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                if (blocked[v]) return {false, (int)ans.size()};\n                cur = v;\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'S') {\n                int rr = row(cur), cc = col(cur);\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int v = id(nr, nc);\n                    if (blocked[v]) break;\n                    rr = nr;\n                    cc = nc;\n                }\n                cur = id(rr, cc);\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'A') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                blocked[v] ^= 1;\n            } else {\n                return {false, (int)ans.size()};\n            }\n        }\n\n        bool ok = (t == M && (int)ans.size() <= 2 * N * M);\n        return {ok, (int)ans.size()};\n    }\n\n    vector<Cmd> solve() {\n        Assign bestAsg = all_none_assign();\n        int bestScore = eval_assignment(bestAsg);\n\n        vector<Assign> seeds;\n        seeds.push_back(bestAsg);\n        seeds.push_back(heuristic_prev_assign());\n        seeds.push_back(greedy_init());\n        for (int i = 0; i < 3; i++) seeds.push_back(random_init());\n\n        for (auto seed : seeds) {\n            if (time_up(0.25)) break;\n            int sc = eval_assignment(seed);\n            auto res = hill_climb(seed, sc);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n        }\n\n        int iter = 0;\n        while (!time_up(0.08)) {\n            Assign cur;\n            if (iter < 4) cur = random_init();\n            else cur = bestAsg;\n\n            int changes = 1 + (rng() % 5);\n            for (int t = 0; t < changes; t++) {\n                int k = 1 + (rng() % (M - 1));\n                int idx = (int)(rng() % cand[k].size());\n                cur[k] = cand[k][idx];\n            }\n\n            int sc = eval_assignment(cur);\n            auto res = hill_climb(cur, sc);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n            iter++;\n        }\n\n        vector<Cmd> ans = build_answer(bestAsg);\n        auto [ok, len] = simulate(ans);\n        if (!ok) {\n            Assign none = all_none_assign();\n            ans = build_answer(none);\n            auto [ok2, len2] = simulate(ans);\n            if (!ok2) {\n                ans.clear();\n                int cur = cells[0];\n                for (int i = 1; i < M; i++) {\n                    int tr = row(cells[i]), tc = col(cells[i]);\n                    int cr = row(cur), cc = col(cur);\n                    while (cr < tr) ans.push_back({'M', 'D'}), cr++;\n                    while (cr > tr) ans.push_back({'M', 'U'}), cr--;\n                    while (cc < tc) ans.push_back({'M', 'R'}), cc++;\n                    while (cc > tc) ans.push_back({'M', 'L'}), cc--;\n                    cur = cells[i];\n                }\n            }\n        }\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<Point> pts(M);\n    for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n    Solver solver(N, M, pts);\n    vector<Cmd> ans = solver.solve();\n\n    for (auto &c : ans) {\n        cout << c.a << ' ' << c.d << '\\n';\n    }\n    return 0;\n}"},"8":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ld = long double;\nstatic constexpr int BOARD = 10000;\nstatic constexpr ld INF_CAP = 1e30L;\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n    int area() const { return (r - l) * (t - b); }\n};\n\nenum Action {\n    EXP_L = 0,\n    EXP_R = 1,\n    EXP_B = 2,\n    EXP_T = 3,\n    SHR_L = 4,\n    SHR_R = 5,\n    SHR_B = 6,\n    SHR_T = 7\n};\n\nstatic constexpr int MASK_EXP =\n    (1 << EXP_L) | (1 << EXP_R) | (1 << EXP_B) | (1 << EXP_T);\nstatic constexpr int MASK_SHR =\n    (1 << SHR_L) | (1 << SHR_R) | (1 << SHR_B) | (1 << SHR_T);\nstatic constexpr int MASK_ALL = MASK_EXP | MASK_SHR;\n\nstruct Move {\n    bool valid = false;\n    int action = 0;\n    int delta = 0;\n    int freecap = 0;\n    int prio = 0;\n    ld gain = 0;\n    ld sec = 0;\n};\n\nstruct PairCand {\n    bool valid = false;\n    int i = -1, j = -1;\n    Rect ri, rj;\n    ld gain = 0;\n    ld sec = 0;\n};\n\nstruct Params {\n    vector<ld> caps;\n    int order_mode = 0;\n    bool reverse_axis = false;\n    array<int, 8> action_prio{};\n};\n\nstruct BSPParams {\n    ld err_w = 0.5L;\n    ld aspect_w = 0.02L;\n    ld step_w = 0.01L;\n    int orient_bias = 0; // -1: horizontal, +1: vertical\n    int top_try = 8;\n    bool smart_bias = true;\n};\n\nstruct SplitCand {\n    bool vertical = true;\n    int cut = 0;\n    vector<int> left, right;\n    ld score = 0;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int mod) {\n        return (int)(next_u64() % (uint64_t)mod);\n    }\n    ld uniform() {\n        return (next_u64() >> 11) * (1.0L / (1ULL << 53));\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n};\n\nstruct Solver {\n    int n;\n    vector<int> xs, ys, rs;\n    vector<ld> sqrs;\n    vector<int> nearest_idx;\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    static bool overlap1d(int l1, int r1, int l2, int r2) {\n        return max(l1, l2) < min(r1, r2);\n    }\n\n    static int ceil_div_int(int a, int b) {\n        return (a + b - 1) / b;\n    }\n\n    ld satisfaction(ld need, ld area) const {\n        if (need <= 0 || area <= 0) return 0;\n        ld t = min(need, area) / max(need, area);\n        ld u = 1.0L - t;\n        return 1.0L - u * u;\n    }\n\n    ld total_score(const vector<Rect>& rects) const {\n        ld res = 0;\n        for (int i = 0; i < n; ++i) res += satisfaction((ld)rs[i], (ld)rects[i].area());\n        return res;\n    }\n\n    long long occupied_area(const vector<Rect>& rects) const {\n        long long s = 0;\n        for (auto &r : rects) s += r.area();\n        return s;\n    }\n\n    vector<Rect> initial_rects() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; ++i) rects[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n        return rects;\n    }\n\n    void apply_move(Rect& rc, int action, int delta) const {\n        switch (action) {\n            case EXP_L: rc.l -= delta; break;\n            case EXP_R: rc.r += delta; break;\n            case EXP_B: rc.b -= delta; break;\n            case EXP_T: rc.t += delta; break;\n            case SHR_L: rc.l += delta; break;\n            case SHR_R: rc.r -= delta; break;\n            case SHR_B: rc.b += delta; break;\n            case SHR_T: rc.t -= delta; break;\n        }\n    }\n\n    ld rect_sec_metric(int i, const Rect& rc) const {\n        int w = rc.r - rc.l;\n        int h = rc.t - rc.b;\n        int area = w * h;\n        int need = rs[i];\n        int nL = xs[i] - rc.l;\n        int nR = rc.r - (xs[i] + 1);\n        int nB = ys[i] - rc.b;\n        int nT = rc.t - (ys[i] + 1);\n        ld aspect = (ld)max(w, h) / (ld)min(w, h);\n        ld imbalance = (ld)(abs(nL - nR) + abs(nB - nT)) / (ld)(w + h);\n        ld err = fabsl((ld)area - (ld)need) / (ld)need;\n        return err + 0.01L * aspect + 0.02L * imbalance;\n    }\n\n    bool better_move(const Move& a, const Move& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const ld EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        if (a.delta < b.delta) return true;\n        if (a.delta > b.delta) return false;\n        if (a.freecap > b.freecap) return true;\n        if (a.freecap < b.freecap) return false;\n        return a.prio < b.prio;\n    }\n\n    bool better_pair(const PairCand& a, const PairCand& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const ld EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        return make_pair(a.i, a.j) < make_pair(b.i, b.j);\n    }\n\n    void compute_expand_limits(int i, const vector<Rect>& rects,\n                               int& maxL, int& maxR, int& maxB, int& maxT) const {\n        const Rect& a = rects[i];\n        int limL = 0, limR = BOARD, limB = 0, limT = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& o = rects[j];\n            if (overlap1d(a.b, a.t, o.b, o.t)) {\n                if (o.r <= a.l) limL = max(limL, o.r);\n                if (o.l >= a.r) limR = min(limR, o.l);\n            }\n            if (overlap1d(a.l, a.r, o.l, o.r)) {\n                if (o.t <= a.b) limB = max(limB, o.t);\n                if (o.b >= a.t) limT = min(limT, o.b);\n            }\n        }\n        maxL = a.l - limL;\n        maxR = limR - a.r;\n        maxB = a.b - limB;\n        maxT = limT - a.t;\n    }\n\n    static void add_target_lengths(vector<int>& v, ld target, int cur, bool expand_mode) {\n        const ld eps = 1e-12L;\n        int f = (int)floor(target + eps);\n        int c = (int)ceil(target - eps);\n        if (expand_mode) {\n            if (f > cur) v.push_back(f);\n            if (c > cur) v.push_back(c);\n        } else {\n            if (f >= 1 && f < cur) v.push_back(f);\n            if (c >= 1 && c < cur) v.push_back(c);\n        }\n    }\n\n    Move best_move_for_rect(int i, const vector<Rect>& rects,\n                            ld shape_cap, bool aggressive,\n                            const array<int, 8>& prio_map,\n                            int allowed_mask) const {\n        const Rect& cur = rects[i];\n        int w = cur.r - cur.l;\n        int h = cur.t - cur.b;\n        int area = w * h;\n        int need = rs[i];\n        ld cur_sat = satisfaction((ld)need, (ld)area);\n\n        int maxL, maxR, maxB, maxT;\n        compute_expand_limits(i, rects, maxL, maxR, maxB, maxT);\n\n        int marginL = xs[i] - cur.l;\n        int marginR = cur.r - (xs[i] + 1);\n        int marginB = ys[i] - cur.b;\n        int marginT = cur.t - (ys[i] + 1);\n\n        vector<Move> cands;\n\n        auto push_candidate = [&](int action, int delta, int freecap) {\n            if (!(allowed_mask & (1 << action))) return;\n            if (delta <= 0) return;\n            for (const auto& mv : cands) {\n                if (mv.action == action && mv.delta == delta) return;\n            }\n            Rect nr = cur;\n            apply_move(nr, action, delta);\n            int nw = nr.r - nr.l;\n            int nh = nr.t - nr.b;\n            int ns = nw * nh;\n            ld g = satisfaction((ld)need, (ld)ns) - cur_sat;\n            if (g <= 1e-18L) return;\n\n            int nL = xs[i] - nr.l;\n            int nR = nr.r - (xs[i] + 1);\n            int nB = ys[i] - nr.b;\n            int nT = nr.t - (ys[i] + 1);\n\n            ld aspect = (ld)max(nw, nh) / (ld)min(nw, nh);\n            ld imbalance = (ld)(abs(nL - nR) + abs(nB - nT)) / (ld)(nw + nh);\n            ld err = fabsl((ld)ns - (ld)need) / (ld)need;\n            ld sec = err + 0.01L * aspect + 0.02L * imbalance;\n\n            Move mv;\n            mv.valid = true;\n            mv.action = action;\n            mv.delta = delta;\n            mv.freecap = freecap;\n            mv.prio = prio_map[action];\n            mv.gain = g;\n            mv.sec = sec;\n            cands.push_back(mv);\n        };\n\n        if (area < need) {\n            ld exactW = (ld)need / (ld)h;\n            ld limitedW = min(exactW, sqrs[i] * shape_cap);\n            vector<int> wtars;\n            add_target_lengths(wtars, limitedW, w, true);\n            add_target_lengths(wtars, exactW, w, true);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_expand_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = Wtar - w;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactW - 1e-12L) > w + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactW - (ld)w - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side(EXP_L, maxL);\n            gen_expand_side(EXP_R, maxR);\n\n            ld exactH = (ld)need / (ld)w;\n            ld limitedH = min(exactH, sqrs[i] * shape_cap);\n            vector<int> htars;\n            add_target_lengths(htars, limitedH, h, true);\n            add_target_lengths(htars, exactH, h, true);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_expand_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = Htar - h;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactH - 1e-12L) > h + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactH - (ld)h - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side_v(EXP_B, maxB);\n            gen_expand_side_v(EXP_T, maxT);\n        } else if (area > need) {\n            ld exactW = (ld)need / (ld)h;\n            vector<int> wtars;\n            add_target_lengths(wtars, exactW, w, false);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_shrink_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = w - Wtar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)w - exactW - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side(SHR_L, marginL);\n            gen_shrink_side(SHR_R, marginR);\n\n            ld exactH = (ld)need / (ld)w;\n            vector<int> htars;\n            add_target_lengths(htars, exactH, h, false);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_shrink_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = h - Htar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)h - exactH - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side_v(SHR_B, marginB);\n            gen_shrink_side_v(SHR_T, marginT);\n        }\n\n        Move best;\n        for (const auto& mv : cands) {\n            if (better_move(mv, best)) best = mv;\n        }\n        return best;\n    }\n\n    vector<int> build_order(const vector<Rect>& rects, int mode, bool reverse_axis) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n\n        if (mode == 0) return ord;\n\n        if (mode == 1) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return rs[a] > rs[b];\n            });\n        } else if (mode == 2) {\n            vector<ld> key(n);\n            for (int i = 0; i < n; ++i) key[i] = 1.0L - satisfaction((ld)rs[i], (ld)rects[i].area());\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        } else if (mode == 3) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] < xs[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] > xs[b];\n                });\n            }\n        } else if (mode == 4) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] < ys[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] > ys[b];\n                });\n            }\n        } else if (mode == 5) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rs[a] - rects[a].area()) > (rs[b] - rects[b].area());\n            });\n        } else if (mode == 6) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rects[a].area() - rs[a]) > (rects[b].area() - rs[b]);\n            });\n        }\n\n        return ord;\n    }\n\n    static ld log_aspect(int w, int h) {\n        ld a = (ld)max(w, h) / (ld)min(w, h);\n        return log(a);\n    }\n\n    vector<SplitCand> generate_bsp_candidates(const vector<int>& ids,\n                                              int lx, int ly, int rx, int ry,\n                                              const BSPParams& par,\n                                              bool optimize_score) {\n        vector<SplitCand> res;\n        int m = (int)ids.size();\n        if (m <= 1) return res;\n\n        int W = rx - lx, H = ry - ly;\n        ld regionArea = (ld)W * (ld)H;\n\n        vector<int> xord = ids, yord = ids;\n        sort(xord.begin(), xord.end(), [&](int a, int b) {\n            if (xs[a] != xs[b]) return xs[a] < xs[b];\n            return ys[a] < ys[b];\n        });\n        sort(yord.begin(), yord.end(), [&](int a, int b) {\n            if (ys[a] != ys[b]) return ys[a] < ys[b];\n            return xs[a] < xs[b];\n        });\n\n        auto make_score = [&](bool vertical, int cut,\n                              const vector<int>& left, const vector<int>& right,\n                              long long reqL, long long reqTot) -> SplitCand {\n            SplitCand c;\n            c.vertical = vertical;\n            c.cut = cut;\n            c.left = left;\n            c.right = right;\n\n            long long reqR = reqTot - reqL;\n\n            ld areaL, areaR;\n            int w1, h1, w2, h2, step;\n            if (vertical) {\n                w1 = cut - lx; h1 = H;\n                w2 = rx - cut; h2 = H;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = H;\n            } else {\n                w1 = W; h1 = cut - ly;\n                w2 = W; h2 = ry - cut;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = W;\n            }\n\n            ld proxy = (ld)left.size() * satisfaction((ld)reqL, areaL)\n                     + (ld)right.size() * satisfaction((ld)reqR, areaR);\n\n            ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n            ld err = fabsl(areaL - scaledL) / regionArea;\n            ld shape = log_aspect(w1, h1) + log_aspect(w2, h2);\n\n            ld score;\n            if (optimize_score) {\n                score = proxy\n                      - par.err_w * err\n                      - par.aspect_w * shape\n                      - par.step_w * ((ld)step / (ld)BOARD);\n\n                if (par.orient_bias == 1 && vertical) score += 1e-3L;\n                if (par.orient_bias == -1 && !vertical) score += 1e-3L;\n                if (par.smart_bias) {\n                    if (W > H && vertical) score += 5e-4L;\n                    if (H > W && !vertical) score += 5e-4L;\n                }\n                score += rng.uniform() * 1e-6L;\n            } else {\n                score = -0.05L * shape - 0.001L * ((ld)step / (ld)BOARD) + rng.uniform() * 1e-6L;\n            }\n            c.score = score;\n            return c;\n        };\n\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[xord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int xL = xs[xord[k - 1]];\n                int xR = xs[xord[k]];\n                int lo = max(lx + 1, xL + 1);\n                int hi = min(rx - 1, xR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, lx + ceil_div_int(k, H));\n                int ahi = min(hi, rx - ceil_div_int(m - k, H));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)lx + scaledL / (ld)H;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    c = max(c, alo);\n                    c = min(c, ahi);\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(xord.begin(), xord.begin() + k);\n                vector<int> right(xord.begin() + k, xord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(true, cut, left, right, reqL, reqTot));\n                }\n            }\n        }\n\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[yord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int yL = ys[yord[k - 1]];\n                int yR = ys[yord[k]];\n                int lo = max(ly + 1, yL + 1);\n                int hi = min(ry - 1, yR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, ly + ceil_div_int(k, W));\n                int ahi = min(hi, ry - ceil_div_int(m - k, W));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)ly + scaledL / (ld)W;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    c = max(c, alo);\n                    c = min(c, ahi);\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(yord.begin(), yord.begin() + k);\n                vector<int> right(yord.begin() + k, yord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(false, cut, left, right, reqL, reqTot));\n                }\n            }\n        }\n\n        sort(res.begin(), res.end(), [&](const SplitCand& a, const SplitCand& b) {\n            return a.score > b.score;\n        });\n        return res;\n    }\n\n    bool partition_rec_simple(const vector<int>& ids,\n                              int lx, int ly, int rx, int ry,\n                              vector<Rect>& out) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        BSPParams dummy;\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, dummy, false);\n        if (cands.empty()) return false;\n\n        for (const auto& c : cands) {\n            if (c.vertical) {\n                if (partition_rec_simple(c.left, lx, ly, c.cut, ry, out) &&\n                    partition_rec_simple(c.right, c.cut, ly, rx, ry, out)) return true;\n            } else {\n                if (partition_rec_simple(c.left, lx, ly, rx, c.cut, out) &&\n                    partition_rec_simple(c.right, lx, c.cut, rx, ry, out)) return true;\n            }\n        }\n        return false;\n    }\n\n    bool partition_rec_opt(const vector<int>& ids,\n                           int lx, int ly, int rx, int ry,\n                           vector<Rect>& out,\n                           const BSPParams& par,\n                           int depth) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, par, true);\n        if (cands.empty()) {\n            return partition_rec_simple(ids, lx, ly, rx, ry, out);\n        }\n\n        int limit = min((int)cands.size(), par.top_try + (depth <= 2 ? 4 : 0));\n        for (int idx = 0; idx < limit; ++idx) {\n            const auto& c = cands[idx];\n            bool ok;\n            if (c.vertical) {\n                ok = partition_rec_opt(c.left, lx, ly, c.cut, ry, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, c.cut, ly, rx, ry, out, par, depth + 1);\n            } else {\n                ok = partition_rec_opt(c.left, lx, ly, rx, c.cut, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, lx, c.cut, rx, ry, out, par, depth + 1);\n            }\n            if (ok) return true;\n        }\n\n        return partition_rec_simple(ids, lx, ly, rx, ry, out);\n    }\n\n    vector<Rect> build_partition_solution(const BSPParams& par) {\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        vector<Rect> rects(n, {0, 0, 0, 0});\n        bool ok = partition_rec_opt(ids, 0, 0, BOARD, BOARD, rects, par, 0);\n        if (!ok) return initial_rects();\n        for (int i = 0; i < n; ++i) {\n            if (!(0 <= rects[i].l && rects[i].l < rects[i].r && rects[i].r <= BOARD &&\n                  0 <= rects[i].b && rects[i].b < rects[i].t && rects[i].t <= BOARD)) {\n                return initial_rects();\n            }\n            if (!(rects[i].l <= xs[i] && xs[i] < rects[i].r &&\n                  rects[i].b <= ys[i] && ys[i] < rects[i].t)) {\n                return initial_rects();\n            }\n        }\n        return rects;\n    }\n\n    ld optimize(vector<Rect>& rects, const Params& params) {\n        long long occ = occupied_area(rects);\n\n        if (occ > 95000000LL) {\n            for (int rep = 0; rep < 2; ++rep) {\n                bool any = false;\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n                if (!any) break;\n            }\n        }\n\n        for (int pass = 0; pass < (int)params.caps.size(); ++pass) {\n            ld cap = params.caps[pass];\n            bool aggressive = (cap > 1e20L);\n            int mode = aggressive ? ((pass & 1) ? 5 : 2) : params.order_mode;\n            vector<int> ord = build_order(rects, mode, params.reverse_axis);\n\n            bool any = false;\n            for (int idx : ord) {\n                Move mv = best_move_for_rect(idx, rects, cap, aggressive,\n                                             params.action_prio, MASK_ALL);\n                if (mv.valid) {\n                    apply_move(rects[idx], mv.action, mv.delta);\n                    any = true;\n                }\n            }\n            if (!any && aggressive) break;\n        }\n\n        for (int rep = 0; rep < 2; ++rep) {\n            bool any = false;\n\n            {\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 5, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_EXP);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 2, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_ALL);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return total_score(rects);\n    }\n\n    array<int, 8> random_action_priority() {\n        vector<int> ord(8);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n        array<int, 8> pr{};\n        for (int i = 0; i < 8; ++i) pr[ord[i]] = i;\n        return pr;\n    }\n\n    Params random_constructive_params() {\n        Params p;\n        ld c0 = 0.85L + 0.40L * rng.uniform();\n        p.caps = {c0, c0 * 1.35L, c0 * 1.8L, c0 * 2.5L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.25L) p.order_mode = 0;\n        else if (u < 0.48L) p.order_mode = 1;\n        else if (u < 0.70L) p.order_mode = 2;\n        else if (u < 0.85L) p.order_mode = 5;\n        else if (u < 0.925L) p.order_mode = 3;\n        else p.order_mode = 4;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_perturb_params() {\n        Params p;\n        ld c0 = 0.95L + 0.55L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, c0 * 2.2L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 2;\n        else if (u < 0.70L) p.order_mode = 5;\n        else if (u < 0.90L) p.order_mode = 6;\n        else p.order_mode = 1;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_partition_params() {\n        Params p;\n        ld c0 = 1.00L + 0.35L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 6;\n        else if (u < 0.75L) p.order_mode = 2;\n        else if (u < 0.92L) p.order_mode = 5;\n        else p.order_mode = 1;\n\n        p.reverse_axis = false;\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params polish_params() {\n        Params p;\n        p.caps = {1.05L, 1.35L, 1.8L, INF_CAP, INF_CAP};\n        p.order_mode = 2;\n        p.reverse_axis = false;\n        for (int i = 0; i < 8; ++i) p.action_prio[i] = i;\n        return p;\n    }\n\n    BSPParams random_bsp_params() {\n        BSPParams p;\n        p.err_w = 0.20L + 0.80L * rng.uniform();\n        p.aspect_w = 0.008L + 0.030L * rng.uniform();\n        p.step_w = 0.000L + 0.030L * rng.uniform();\n        p.orient_bias = rng.next_int(3) - 1;\n        p.top_try = 5 + rng.next_int(6);\n        p.smart_bias = true;\n        return p;\n    }\n\n    int weighted_pick(const vector<ld>& w, const vector<char>& banned) {\n        ld sum = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) sum += w[i];\n        if (sum <= 0) {\n            vector<int> cand;\n            for (int i = 0; i < n; ++i) if (!banned[i]) cand.push_back(i);\n            if (cand.empty()) return -1;\n            return cand[rng.next_int((int)cand.size())];\n        }\n        ld z = rng.uniform() * sum;\n        ld acc = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) {\n            acc += w[i];\n            if (acc >= z) return i;\n        }\n        for (int i = n - 1; i >= 0; --i) if (!banned[i]) return i;\n        return -1;\n    }\n\n    vector<Rect> perturb_from_best(const vector<Rect>& best) {\n        vector<Rect> seed = best;\n        vector<ld> w(n);\n        for (int i = 0; i < n; ++i) {\n            w[i] = 0.01L + (1.0L - satisfaction((ld)rs[i], (ld)best[i].area()));\n        }\n        vector<char> banned(n, 0);\n        int k = 1 + rng.next_int(min(5, n));\n\n        auto reset_rect = [&](int idx) {\n            if (idx < 0) return;\n            seed[idx] = {xs[idx], ys[idx], xs[idx] + 1, ys[idx] + 1};\n            banned[idx] = 1;\n        };\n\n        for (int it = 0; it < k; ++it) {\n            int idx = weighted_pick(w, banned);\n            if (idx < 0) break;\n            reset_rect(idx);\n            if (nearest_idx[idx] != -1 && rng.next_int(100) < 55) {\n                reset_rect(nearest_idx[idx]);\n            }\n        }\n        return seed;\n    }\n\n    static void add_unique_int(vector<int>& v, int x) {\n        v.push_back(x);\n    }\n\n    bool choose_interval_around_anchor(int L, int R, int anchor, int len, int& outL) const {\n        int lo = max(L, anchor - len + 1);\n        int hi = min(anchor, R - len);\n        if (lo > hi) return false;\n        int ideal = anchor - (len - 1) / 2;\n        if (ideal < lo) ideal = lo;\n        if (ideal > hi) ideal = hi;\n        outL = ideal;\n        return true;\n    }\n\n    pair<bool, Rect> best_rebuild_candidate(int i, const vector<Rect>& rects, bool allow_equal) const {\n        const Rect& cur = rects[i];\n        Rect best = cur;\n        ld best_sat = satisfaction((ld)rs[i], (ld)cur.area());\n        ld best_sec = rect_sec_metric(i, cur);\n\n        auto consider = [&](const Rect& nr) {\n            if (!(0 <= nr.l && nr.l < nr.r && nr.r <= BOARD &&\n                  0 <= nr.b && nr.b < nr.t && nr.t <= BOARD)) return;\n            if (!(nr.l <= xs[i] && xs[i] < nr.r && nr.b <= ys[i] && ys[i] < nr.t)) return;\n\n            ld nsat = satisfaction((ld)rs[i], (ld)nr.area());\n            ld nsec = rect_sec_metric(i, nr);\n\n            const ld EPS = 1e-18L;\n            bool better = false;\n            if (nsat > best_sat + EPS) better = true;\n            else if (allow_equal && fabsl(nsat - best_sat) <= EPS && nsec + 1e-15L < best_sec) better = true;\n\n            if (better) {\n                best = nr;\n                best_sat = nsat;\n                best_sec = nsec;\n            }\n        };\n\n        {\n            vector<int> Bs, Ts;\n            Bs.reserve(n + 4);\n            Ts.reserve(n + 4);\n            add_unique_int(Bs, 0);\n            add_unique_int(Bs, cur.b);\n            add_unique_int(Ts, BOARD);\n            add_unique_int(Ts, cur.t);\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.t <= ys[i]) add_unique_int(Bs, o.t);\n                if (o.b >= ys[i] + 1) add_unique_int(Ts, o.b);\n            }\n            sort(Bs.begin(), Bs.end());\n            Bs.erase(unique(Bs.begin(), Bs.end()), Bs.end());\n            sort(Ts.begin(), Ts.end());\n            Ts.erase(unique(Ts.begin(), Ts.end()), Ts.end());\n\n            int curW = cur.r - cur.l;\n            for (int b : Bs) {\n                if (b > ys[i]) continue;\n                for (int t : Ts) {\n                    if (t < ys[i] + 1) continue;\n                    if (b >= t) continue;\n\n                    int L = 0, R = BOARD;\n                    bool valid = true;\n                    for (int j = 0; j < n; ++j) if (j != i) {\n                        const Rect& o = rects[j];\n                        if (!overlap1d(b, t, o.b, o.t)) continue;\n\n                        if (overlap1d(o.l, o.r, xs[i], xs[i] + 1)) {\n                            valid = false;\n                            break;\n                        }\n                        if (o.r <= xs[i]) L = max(L, o.r);\n                        else if (o.l >= xs[i] + 1) R = min(R, o.l);\n                        else {\n                            valid = false;\n                            break;\n                        }\n                    }\n                    if (!valid || L >= R) continue;\n\n                    int h = t - b;\n                    int wcap = R - L;\n                    if (wcap <= 0) continue;\n\n                    vector<int> candW;\n                    auto addW = [&](int W) {\n                        if (1 <= W && W <= wcap) candW.push_back(W);\n                    };\n                    ld tw = (ld)rs[i] / (ld)h;\n                    addW((int)floor(tw + 1e-12L));\n                    addW((int)ceil(tw - 1e-12L));\n                    addW((int)llround(tw));\n                    addW(curW);\n                    addW(wcap);\n                    sort(candW.begin(), candW.end());\n                    candW.erase(unique(candW.begin(), candW.end()), candW.end());\n\n                    for (int W : candW) {\n                        int l;\n                        if (!choose_interval_around_anchor(L, R, xs[i], W, l)) continue;\n                        Rect nr{l, b, l + W, t};\n                        consider(nr);\n                    }\n                }\n            }\n        }\n\n        {\n            vector<int> Ls, Rs;\n            Ls.reserve(n + 4);\n            Rs.reserve(n + 4);\n            add_unique_int(Ls, 0);\n            add_unique_int(Ls, cur.l);\n            add_unique_int(Rs, BOARD);\n            add_unique_int(Rs, cur.r);\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.r <= xs[i]) add_unique_int(Ls, o.r);\n                if (o.l >= xs[i] + 1) add_unique_int(Rs, o.l);\n            }\n            sort(Ls.begin(), Ls.end());\n            Ls.erase(unique(Ls.begin(), Ls.end()), Ls.end());\n            sort(Rs.begin(), Rs.end());\n            Rs.erase(unique(Rs.begin(), Rs.end()), Rs.end());\n\n            int curH = cur.t - cur.b;\n            for (int l : Ls) {\n                if (l > xs[i]) continue;\n                for (int r : Rs) {\n                    if (r < xs[i] + 1) continue;\n                    if (l >= r) continue;\n\n                    int B = 0, T = BOARD;\n                    bool valid = true;\n                    for (int j = 0; j < n; ++j) if (j != i) {\n                        const Rect& o = rects[j];\n                        if (!overlap1d(l, r, o.l, o.r)) continue;\n\n                        if (overlap1d(o.b, o.t, ys[i], ys[i] + 1)) {\n                            valid = false;\n                            break;\n                        }\n                        if (o.t <= ys[i]) B = max(B, o.t);\n                        else if (o.b >= ys[i] + 1) T = min(T, o.b);\n                        else {\n                            valid = false;\n                            break;\n                        }\n                    }\n                    if (!valid || B >= T) continue;\n\n                    int w = r - l;\n                    int hcap = T - B;\n                    if (hcap <= 0) continue;\n\n                    vector<int> candH;\n                    auto addH = [&](int H) {\n                        if (1 <= H && H <= hcap) candH.push_back(H);\n                    };\n                    ld th = (ld)rs[i] / (ld)w;\n                    addH((int)floor(th + 1e-12L));\n                    addH((int)ceil(th - 1e-12L));\n                    addH((int)llround(th));\n                    addH(curH);\n                    addH(hcap);\n                    sort(candH.begin(), candH.end());\n                    candH.erase(unique(candH.begin(), candH.end()), candH.end());\n\n                    for (int H : candH) {\n                        int b;\n                        if (!choose_interval_around_anchor(B, T, ys[i], H, b)) continue;\n                        Rect nr{l, b, r, b + H};\n                        consider(nr);\n                    }\n                }\n            }\n        }\n\n        if (best.l == cur.l && best.b == cur.b && best.r == cur.r && best.t == cur.t) {\n            return {false, cur};\n        }\n        return {true, best};\n    }\n\n    PairCand best_pair_rebuild_candidate(int i, int j, const vector<Rect>& rects, bool allow_equal) const {\n        PairCand res;\n        if (i == j) return res;\n\n        const Rect& a0 = rects[i];\n        const Rect& b0 = rects[j];\n        int L = min(a0.l, b0.l);\n        int B = min(a0.b, b0.b);\n        int R = max(a0.r, b0.r);\n        int T = max(a0.t, b0.t);\n\n        for (int k = 0; k < n; ++k) if (k != i && k != j) {\n            const Rect& o = rects[k];\n            if (overlap1d(L, R, o.l, o.r) && overlap1d(B, T, o.b, o.t)) {\n                return res;\n            }\n        }\n\n        ld cur_sat = satisfaction((ld)rs[i], (ld)a0.area()) + satisfaction((ld)rs[j], (ld)b0.area());\n        ld cur_sec = rect_sec_metric(i, a0) + rect_sec_metric(j, b0);\n\n        ld best_sat = cur_sat;\n        ld best_sec = cur_sec;\n        Rect best_i = a0, best_j = b0;\n\n        auto consider = [&](const Rect& ri, const Rect& rj) {\n            if (!(0 <= ri.l && ri.l < ri.r && ri.r <= BOARD && 0 <= ri.b && ri.b < ri.t && ri.t <= BOARD)) return;\n            if (!(0 <= rj.l && rj.l < rj.r && rj.r <= BOARD && 0 <= rj.b && rj.b < rj.t && rj.t <= BOARD)) return;\n            if (!(ri.l <= xs[i] && xs[i] < ri.r && ri.b <= ys[i] && ys[i] < ri.t)) return;\n            if (!(rj.l <= xs[j] && xs[j] < rj.r && rj.b <= ys[j] && ys[j] < rj.t)) return;\n            if (overlap1d(ri.l, ri.r, rj.l, rj.r) && overlap1d(ri.b, ri.t, rj.b, rj.t)) return;\n\n            ld nsat = satisfaction((ld)rs[i], (ld)ri.area()) + satisfaction((ld)rs[j], (ld)rj.area());\n            ld nsec = rect_sec_metric(i, ri) + rect_sec_metric(j, rj);\n\n            const ld EPS = 1e-18L;\n            bool better = false;\n            if (nsat > best_sat + EPS) better = true;\n            else if (allow_equal && fabsl(nsat - best_sat) <= EPS && nsec + 1e-15L < best_sec) better = true;\n\n            if (better) {\n                best_sat = nsat;\n                best_sec = nsec;\n                best_i = ri;\n                best_j = rj;\n            }\n        };\n\n        auto push_cut = [&](vector<int>& v, int c, int lo, int hi) {\n            if (c < lo) c = lo;\n            if (c > hi) c = hi;\n            v.push_back(c);\n        };\n\n        if (xs[i] < xs[j]) {\n            int lo = xs[i] + 1;\n            int hi = xs[j];\n            if (lo <= hi) {\n                int H = T - B;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)L + (ld)rs[i] / (ld)H;\n                ld z2 = (ld)R - (ld)rs[j] / (ld)H;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (a0.r == b0.l) push_cut(cuts, a0.r, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, B, c, T}, Rect{c, B, R, T});\n                }\n            }\n        } else if (xs[j] < xs[i]) {\n            int lo = xs[j] + 1;\n            int hi = xs[i];\n            if (lo <= hi) {\n                int H = T - B;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)L + (ld)rs[j] / (ld)H;\n                ld z2 = (ld)R - (ld)rs[i] / (ld)H;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (b0.r == a0.l) push_cut(cuts, b0.r, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{c, B, R, T}, Rect{L, B, c, T});\n                }\n            }\n        }\n\n        if (ys[i] < ys[j]) {\n            int lo = ys[i] + 1;\n            int hi = ys[j];\n            if (lo <= hi) {\n                int W = R - L;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)B + (ld)rs[i] / (ld)W;\n                ld z2 = (ld)T - (ld)rs[j] / (ld)W;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (a0.t == b0.b) push_cut(cuts, a0.t, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, B, R, c}, Rect{L, c, R, T});\n                }\n            }\n        } else if (ys[j] < ys[i]) {\n            int lo = ys[j] + 1;\n            int hi = ys[i];\n            if (lo <= hi) {\n                int W = R - L;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)B + (ld)rs[j] / (ld)W;\n                ld z2 = (ld)T - (ld)rs[i] / (ld)W;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (b0.t == a0.b) push_cut(cuts, b0.t, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, c, R, T}, Rect{L, B, R, c});\n                }\n            }\n        }\n\n        const ld EPS = 1e-18L;\n        if (best_sat > cur_sat + EPS || (allow_equal && fabsl(best_sat - cur_sat) <= EPS && best_sec + 1e-15L < cur_sec)) {\n            res.valid = true;\n            res.i = i;\n            res.j = j;\n            res.ri = best_i;\n            res.rj = best_j;\n            res.gain = best_sat - cur_sat;\n            res.sec = best_sec;\n        }\n        return res;\n    }\n\n    bool rebuild_pass(vector<Rect>& rects, int K, bool allow_equal) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        K = min(K, n);\n        partial_sort(ord.begin(), ord.begin() + K, ord.end(), [&](int a, int b) {\n            ld da = 1.0L - satisfaction((ld)rs[a], (ld)rects[a].area());\n            ld db = 1.0L - satisfaction((ld)rs[b], (ld)rects[b].area());\n            if (fabsl(da - db) > 1e-18L) return da > db;\n            return rs[a] > rs[b];\n        });\n\n        bool any = false;\n        for (int z = 0; z < K; ++z) {\n            int i = ord[z];\n            auto [ok, nr] = best_rebuild_candidate(i, rects, allow_equal);\n            if (ok) {\n                rects[i] = nr;\n                any = true;\n            }\n        }\n        return any;\n    }\n\n    bool pair_rebuild_pass(vector<Rect>& rects, int K, bool allow_equal) {\n        K = min(K, n);\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        partial_sort(ord.begin(), ord.begin() + K, ord.end(), [&](int a, int b) {\n            ld da = 1.0L - satisfaction((ld)rs[a], (ld)rects[a].area());\n            ld db = 1.0L - satisfaction((ld)rs[b], (ld)rects[b].area());\n            if (fabsl(da - db) > 1e-18L) return da > db;\n            return rs[a] > rs[b];\n        });\n\n        vector<char> bad(n, 0);\n        for (int z = 0; z < K; ++z) bad[ord[z]] = 1;\n\n        PairCand best;\n        for (int z = 0; z < K; ++z) {\n            int i = ord[z];\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (bad[j] && j < i) continue;\n                PairCand cand = best_pair_rebuild_candidate(i, j, rects, allow_equal);\n                if (better_pair(cand, best)) best = cand;\n            }\n        }\n\n        if (best.valid) {\n            rects[best.i] = best.ri;\n            rects[best.j] = best.rj;\n            return true;\n        }\n        return false;\n    }\n\n    ld elapsed_sec() const {\n        return chrono::duration<ld>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    static bool same_rects(const vector<Rect>& a, const vector<Rect>& b) {\n        if (a.size() != b.size()) return false;\n        for (size_t i = 0; i < a.size(); ++i) {\n            if (a[i].l != b[i].l || a[i].b != b[i].b || a[i].r != b[i].r || a[i].t != b[i].t) return false;\n        }\n        return true;\n    }\n\n    void update_elites(const vector<Rect>& cur, ld sc,\n                       vector<Rect>& best_rects, ld& best_score,\n                       vector<Rect>& second_rects, ld& second_score) {\n        const ld EPS = 1e-18L;\n        if (sc > best_score + EPS) {\n            if (!same_rects(best_rects, cur) && best_score > second_score + EPS) {\n                second_score = best_score;\n                second_rects = best_rects;\n            }\n            best_score = sc;\n            best_rects = cur;\n        } else if (sc + EPS < best_score && sc > second_score + EPS) {\n            if (!same_rects(best_rects, cur)) {\n                second_score = sc;\n                second_rects = cur;\n            }\n        }\n    }\n\n    bool intensify_candidate(vector<Rect>& cand, ld& cand_score,\n                             int pairK, int singleK) {\n        bool any = false;\n        any |= pair_rebuild_pass(cand, min(pairK, n), true);\n        any |= rebuild_pass(cand, min(singleK, n), true);\n        if (!any) return false;\n        cand_score = optimize(cand, polish_params());\n        return true;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        xs.resize(n);\n        ys.resize(n);\n        rs.resize(n);\n        sqrs.resize(n);\n\n        uint64_t seed = 1469598103934665603ULL;\n        for (int i = 0; i < n; ++i) {\n            cin >> xs[i] >> ys[i] >> rs[i];\n            sqrs[i] = sqrt((ld)rs[i]);\n            seed ^= (uint64_t)(xs[i] + 1) * 1000003ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(ys[i] + 7) * 1000033ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(rs[i] + 13) * 1000037ULL;\n            seed *= 1099511628211ULL;\n        }\n        rng = XorShift64(seed);\n\n        nearest_idx.assign(n, -1);\n        for (int i = 0; i < n; ++i) {\n            long long bestd = (1LL << 62);\n            for (int j = 0; j < n; ++j) if (i != j) {\n                long long dx = xs[i] - xs[j];\n                long long dy = ys[i] - ys[j];\n                long long d = dx * dx + dy * dy;\n                if (d < bestd) {\n                    bestd = d;\n                    nearest_idx[i] = j;\n                }\n            }\n        }\n\n        start_time = chrono::steady_clock::now();\n\n        vector<Rect> best_rects = initial_rects();\n        ld best_score = total_score(best_rects);\n\n        vector<Rect> second_rects = best_rects;\n        ld second_score = -1;\n\n        for (int t = 0; t < 2 && elapsed_sec() < 1.35L; ++t) {\n            vector<Rect> cur = initial_rects();\n            Params p = random_constructive_params();\n            ld sc = optimize(cur, p);\n            update_elites(cur, sc, best_rects, best_score, second_rects, second_score);\n        }\n\n        for (int t = 0; t < 4 && elapsed_sec() < 2.30L; ++t) {\n            vector<Rect> cur = build_partition_solution(random_bsp_params());\n            Params p = random_partition_params();\n            ld sc = optimize(cur, p);\n            update_elites(cur, sc, best_rects, best_score, second_rects, second_score);\n        }\n\n        int iter = 0;\n        while (elapsed_sec() < 4.56L) {\n            vector<Rect> cur;\n            Params p;\n\n            if (iter < 6) {\n                if (iter & 1) {\n                    cur = build_partition_solution(random_bsp_params());\n                    p = random_partition_params();\n                } else {\n                    cur = initial_rects();\n                    p = random_constructive_params();\n                }\n            } else {\n                ld u = rng.uniform();\n                if (u < 0.18L) {\n                    cur = initial_rects();\n                    p = random_constructive_params();\n                } else if (u < 0.42L) {\n                    cur = build_partition_solution(random_bsp_params());\n                    p = random_partition_params();\n                } else {\n                    const vector<Rect>& base =\n                        (second_score > 0 && rng.next_int(100) < 25) ? second_rects : best_rects;\n                    cur = perturb_from_best(base);\n                    p = random_perturb_params();\n                }\n            }\n\n            ld sc = optimize(cur, p);\n            bool strict_improve = (sc > best_score + 1e-18L);\n\n            if (strict_improve) {\n                update_elites(cur, sc, best_rects, best_score, second_rects, second_score);\n\n                if (elapsed_sec() < 4.28L) {\n                    vector<Rect> tmp = best_rects;\n                    ld sc2 = best_score;\n                    if (intensify_candidate(tmp, sc2, 12, 8)) {\n                        update_elites(tmp, sc2, best_rects, best_score, second_rects, second_score);\n                    }\n                }\n            } else {\n                update_elites(cur, sc, best_rects, best_score, second_rects, second_score);\n\n                // Occasionally polish a near-best candidate too.\n                if ((iter % 6 == 0) && elapsed_sec() < 4.18L && sc + 0.015L >= best_score) {\n                    vector<Rect> tmp = cur;\n                    ld sc2 = sc;\n                    if (intensify_candidate(tmp, sc2, 10, 6)) {\n                        update_elites(tmp, sc2, best_rects, best_score, second_rects, second_score);\n                    }\n                }\n            }\n\n            ++iter;\n        }\n\n        while (elapsed_sec() < 4.93L) {\n            vector<Rect> tmp = best_rects;\n            bool any = false;\n            any |= pair_rebuild_pass(tmp, min(14, n), true);\n            if (elapsed_sec() >= 4.93L) break;\n            any |= pair_rebuild_pass(tmp, min(14, n), true);\n            if (elapsed_sec() >= 4.93L) break;\n            any |= rebuild_pass(tmp, min(10, n), true);\n            if (!any) break;\n\n            ld sc = optimize(tmp, polish_params());\n            if (sc > best_score + 1e-18L) {\n                update_elites(tmp, sc, best_rects, best_score, second_rects, second_score);\n            } else {\n                break;\n            }\n        }\n\n        for (int i = 0; i < n; ++i) {\n            cout << best_rects[i].l << ' ' << best_rects[i].b << ' '\n                 << best_rects[i].r << ' ' << best_rects[i].t << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50;\nstatic constexpr int W = 50;\nstatic constexpr int V = H * W;\n\nusing Clock = chrono::steady_clock;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463325252ull;\n    void seed(uint64_t s) { x = s ? s : 88172645463325252ull; }\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\ninline int id(int i, int j) { return i * W + j; }\n\nstruct CompStat {\n    int tiles;\n    int ub;\n};\n\nstruct Params {\n    int lookDepth = 6;\n    int tilesMargin = 0;\n    int ubMargin = 0;\n    int lookMargin = 0;\n    bool deterministic = false;\n    int style = 0; // 0: safe/length-biased, 1: score-biased\n};\n\nstruct Path {\n    vector<int> pos;\n    vector<int> prefixScore;\n    vector<unsigned char> branchCnt;\n    vector<int> branchPoints;\n    int score = 0;\n};\n\nstruct MoveInfo {\n    int v = -1;\n    int addScore = 0;\n    int addLen = 0;\n    int reachTiles = 0;\n    int reachUb = 0;\n    int deg = 0;\n    int look = INT_MIN;\n\n    // weak branch-richness features at corridor endpoint\n    int altTiles = 0;\n    int altUb = 0;\n};\n\nint si, sj, startIdx;\nint tileId[V];\nint pval[V];\nint M;\n\nint adjList[V][4];\nunsigned char adjCnt[V];\n\nvector<int> tileMaxVal;\nvector<unsigned char> usedTile;\nvector<unsigned char> tmpUsed;\n\nint visSq[V];\nvector<int> visTile;\nint bfsStamp = 1;\nint tileStamp = 1;\nint qbuf[V];\n\nClock::time_point globalDeadline;\n\n// opening search\nvector<int> openingCur, openingBest;\nlong long openingBestUB = -1;\nint openingBestTiles = -1;\nint openingBestAcc = -1;\nClock::time_point openingDeadline;\nbool openingTimeout = false;\nint openingNodes = 0;\nstatic constexpr int OPENING_NODE_LIMIT = 13000;\n\ninline int avail_neighbors(int u, int out[4]) {\n    int c = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) out[c++] = v;\n    }\n    return c;\n}\n\ninline CompStat component_stat(int s) {\n    const int st = tileId[s];\n    ++bfsStamp;\n    ++tileStamp;\n\n    int head = 0, tail = 0;\n    qbuf[tail++] = s;\n    visSq[s] = bfsStamp;\n    visTile[st] = tileStamp;\n\n    int tiles = 1;\n    int ub = pval[s];\n\n    while (head < tail) {\n        int u = qbuf[head++];\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            int tv = tileId[v];\n            if (tv == st || usedTile[tv]) continue;\n            if (visSq[v] != bfsStamp) {\n                visSq[v] = bfsStamp;\n                qbuf[tail++] = v;\n            }\n            if (visTile[tv] != tileStamp) {\n                visTile[tv] = tileStamp;\n                ++tiles;\n                ub += tileMaxVal[tv];\n            }\n        }\n    }\n    return {tiles, ub};\n}\n\ninline void best_future_from_current(int u, int& bestTiles, int& bestUb) {\n    bestTiles = 0;\n    bestUb = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) {\n            auto cs = component_stat(v);\n            if (cs.tiles > bestTiles) bestTiles = cs.tiles;\n            if (cs.ub > bestUb) bestUb = cs.ub;\n        }\n    }\n}\n\nint local_dfs(int u, int depth) {\n    int trail[16];\n    int tcnt = 0;\n    int gain = 0;\n\n    while (depth > 0) {\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n        if (ccnt == 0) {\n            for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n            return gain;\n        }\n        if (ccnt == 1) {\n            int v = cand[0];\n            int tv = tileId[v];\n            usedTile[tv] = 1;\n            trail[tcnt++] = tv;\n            gain += pval[v];\n            u = v;\n            --depth;\n            continue;\n        }\n        break;\n    }\n\n    if (depth == 0) {\n        for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n        return gain;\n    }\n\n    struct Cand {\n        int v;\n        int pri;\n    };\n    Cand cand2[4];\n    int n2 = 0;\n\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        int tv = tileId[v];\n        if (usedTile[tv]) continue;\n        usedTile[tv] = 1;\n        int out[4];\n        int deg = avail_neighbors(v, out);\n        usedTile[tv] = 0;\n        cand2[n2++] = {v, pval[v] * 8 + deg * 5};\n    }\n\n    sort(cand2, cand2 + n2, [](const Cand& a, const Cand& b) {\n        return a.pri > b.pri;\n    });\n\n    int best = 0;\n    for (int i = 0; i < n2; ++i) {\n        int v = cand2[i].v;\n        int tv = tileId[v];\n        usedTile[tv] = 1;\n        int sc = pval[v] + local_dfs(v, depth - 1);\n        usedTile[tv] = 0;\n        if (sc > best) best = sc;\n    }\n\n    for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n    return gain + best;\n}\n\nvoid preview_move_corridor(int v, MoveInfo& info) {\n    info = MoveInfo();\n    info.v = v;\n\n    int trail[V];\n    int tcnt = 0;\n    int cur = v;\n    int addScore = 0;\n    int addLen = 0;\n\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        trail[tcnt++] = tv;\n        addScore += pval[cur];\n        ++addLen;\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) {\n            int bestTiles1 = 0, bestTiles2 = 0;\n            int bestUb1 = 0, bestUb2 = 0;\n\n            for (int i = 0; i < ccnt; ++i) {\n                auto cs = component_stat(cand[i]);\n                if (cs.tiles > bestTiles1 || (cs.tiles == bestTiles1 && cs.ub > bestUb1)) {\n                    bestTiles2 = bestTiles1;\n                    bestUb2 = bestUb1;\n                    bestTiles1 = cs.tiles;\n                    bestUb1 = cs.ub;\n                } else if (cs.tiles > bestTiles2 || (cs.tiles == bestTiles2 && cs.ub > bestUb2)) {\n                    bestTiles2 = cs.tiles;\n                    bestUb2 = cs.ub;\n                }\n            }\n\n            info.addScore = addScore;\n            info.addLen = addLen;\n            info.deg = ccnt;\n            info.reachTiles = addLen + bestTiles1;\n            info.reachUb = addScore + bestUb1;\n            info.altTiles = bestTiles2;\n            info.altUb = bestUb2;\n            break;\n        }\n        cur = cand[0];\n    }\n\n    for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n}\n\nint look_move_corridor(int v, int totalDepth) {\n    int trail[V];\n    int tcnt = 0;\n    int cur = v;\n    int addScore = 0;\n    int addLen = 0;\n\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        trail[tcnt++] = tv;\n        addScore += pval[cur];\n        ++addLen;\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) {\n            int rem = max(0, totalDepth - addLen);\n            int res = addScore + local_dfs(cur, rem);\n            for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n            return res;\n        }\n        cur = cand[0];\n    }\n}\n\nvoid commit_corridor(Path& res, int v) {\n    int cur = v;\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        res.pos.push_back(cur);\n        res.score += pval[cur];\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) break;\n        cur = cand[0];\n    }\n}\n\nbool better_move(const MoveInfo& a, const MoveInfo& b, int step, const Params& prm) {\n    if (prm.style == 0) {\n        if (prm.deterministic || step < 80) {\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.altUb != b.altUb) return a.altUb > b.altUb;\n            if (a.look != b.look) return a.look > b.look;\n        } else if (step < 250) {\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n        } else {\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n        }\n    } else {\n        if (prm.deterministic || step < 80) {\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altUb != b.altUb) return a.altUb > b.altUb;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n        } else if (step < 250) {\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.altUb != b.altUb) return a.altUb > b.altUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n        } else {\n            if (a.look != b.look) return a.look > b.look;\n            if (a.addScore != b.addScore) return a.addScore > b.addScore;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n        }\n    }\n    if (a.addScore != b.addScore) return a.addScore > b.addScore;\n    if (a.deg != b.deg) return a.deg > b.deg;\n    return pval[a.v] > pval[b.v];\n}\n\nPath build_path(vector<int> pos, int score, const Params& prm, const Clock::time_point& deadline) {\n    Path res;\n    res.pos = std::move(pos);\n    res.score = score;\n    res.pos.reserve(V);\n\n    int it = 0;\n    while (true) {\n        if ((it++ & 31) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n\n        int u = res.pos.back();\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n        if (ccnt == 0) break;\n\n        if (ccnt == 1) {\n            commit_corridor(res, cand[0]);\n            continue;\n        }\n\n        MoveInfo info[4];\n        for (int i = 0; i < ccnt; ++i) preview_move_corridor(cand[i], info[i]);\n\n        int step = (int)res.pos.size();\n\n        int baseTM, baseUM, baseLM;\n        if (prm.deterministic || step < 60) {\n            baseTM = 0; baseUM = 40; baseLM = 4;\n        } else if (step < 180) {\n            baseTM = 1; baseUM = 120; baseLM = 8;\n        } else if (step < 400) {\n            baseTM = 2; baseUM = 220; baseLM = 12;\n        } else {\n            baseTM = 4; baseUM = 450; baseLM = 18;\n        }\n\n        if (prm.style == 1) {\n            baseTM += 1;\n            baseUM = max(0, baseUM - 35);\n            baseLM = max(2, baseLM - 1);\n        }\n\n        int tm = baseTM + prm.tilesMargin;\n        int um = baseUM + prm.ubMargin;\n        int lm = baseLM + prm.lookMargin;\n\n        int lookDepth = prm.lookDepth + (step < 30 ? 2 : step < 90 ? 1 : 0);\n        if (prm.deterministic) ++lookDepth;\n        lookDepth = min(lookDepth, 9);\n\n        int chosen = info[0].v;\n\n        if (prm.deterministic || step < 26) {\n            for (int i = 0; i < ccnt; ++i) info[i].look = look_move_corridor(info[i].v, lookDepth);\n            int bestIdx = 0;\n            for (int i = 1; i < ccnt; ++i) {\n                if (better_move(info[i], info[bestIdx], step, prm)) bestIdx = i;\n            }\n            chosen = info[bestIdx].v;\n        } else {\n            int alive[4];\n            int acnt = ccnt;\n            for (int i = 0; i < ccnt; ++i) alive[i] = i;\n\n            int bestTiles = -1;\n            for (int i = 0; i < acnt; ++i) bestTiles = max(bestTiles, info[alive[i]].reachTiles);\n            {\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].reachTiles >= bestTiles - tm) nxt[ncnt++] = idx;\n                }\n                for (int i = 0; i < ncnt; ++i) alive[i] = nxt[i];\n                acnt = ncnt;\n            }\n\n            int bestUb = -1;\n            for (int i = 0; i < acnt; ++i) bestUb = max(bestUb, info[alive[i]].reachUb);\n            {\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].reachUb >= bestUb - um) nxt[ncnt++] = idx;\n                }\n                for (int i = 0; i < ncnt; ++i) alive[i] = nxt[i];\n                acnt = ncnt;\n            }\n\n            for (int i = 0; i < acnt; ++i) {\n                int idx = alive[i];\n                info[idx].look = look_move_corridor(info[idx].v, lookDepth);\n            }\n\n            int bestLook = INT_MIN;\n            for (int i = 0; i < acnt; ++i) bestLook = max(bestLook, info[alive[i]].look);\n\n            int fin[4], fcnt = 0;\n            int w[4], wsum = 0;\n            for (int i = 0; i < acnt; ++i) {\n                int idx = alive[i];\n                if (info[idx].look >= bestLook - lm) {\n                    fin[fcnt] = idx;\n                    int ww = info[idx].look - (bestLook - lm) + 1;\n                    ww += info[idx].deg * 2;\n                    ww += info[idx].addScore / (prm.style == 1 ? 8 : 12);\n                    ww += min(6, info[idx].altTiles / 35);\n                    if (prm.style == 1) ww += min(6, info[idx].altUb / 250);\n                    if (ww < 1) ww = 1;\n                    w[fcnt] = ww;\n                    wsum += ww;\n                    ++fcnt;\n                }\n            }\n\n            int r = rng.next_int(1, wsum);\n            chosen = info[fin[0]].v;\n            for (int i = 0; i < fcnt; ++i) {\n                r -= w[i];\n                if (r <= 0) {\n                    chosen = info[fin[i]].v;\n                    break;\n                }\n            }\n        }\n\n        commit_corridor(res, chosen);\n    }\n\n    return res;\n}\n\nvoid prepare_path(Path& path) {\n    int n = (int)path.pos.size();\n    path.prefixScore.assign(n, 0);\n    path.branchCnt.assign(n, 0);\n    path.branchPoints.clear();\n\n    fill(tmpUsed.begin(), tmpUsed.end(), 0);\n    int s = 0;\n    for (int i = 0; i < n; ++i) {\n        int u = path.pos[i];\n        tmpUsed[tileId[u]] = 1;\n        s += pval[u];\n        path.prefixScore[i] = s;\n\n        int cnt = 0;\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            if (!tmpUsed[tileId[v]]) ++cnt;\n        }\n        path.branchCnt[i] = (unsigned char)cnt;\n        if (cnt >= 2) path.branchPoints.push_back(i);\n    }\n    path.score = s;\n}\n\nbool better_path(const Path& a, const Path& b) {\n    if (a.score != b.score) return a.score > b.score;\n    return a.pos.size() > b.pos.size();\n}\n\nvoid add_elite(vector<Path>& elites, Path cand, int keep = 7) {\n    prepare_path(cand);\n    elites.push_back(std::move(cand));\n    sort(elites.begin(), elites.end(), [](const Path& a, const Path& b) {\n        return better_path(a, b);\n    });\n    if ((int)elites.size() > keep) elites.resize(keep);\n}\n\nint choose_elite(const vector<Path>& elites) {\n    int n = (int)elites.size();\n    int sum = 0;\n    for (int i = 0; i < n; ++i) sum += (n - i);\n    int r = rng.next_int(1, sum);\n    for (int i = 0; i < n; ++i) {\n        r -= (n - i);\n        if (r <= 0) return i;\n    }\n    return 0;\n}\n\nint choose_cut(const Path& path) {\n    if (path.branchPoints.empty()) return 0;\n    const auto& bp = path.branchPoints;\n    int n = (int)bp.size();\n\n    int l = 0, r = n - 1;\n    if (n >= 3) {\n        int a = n / 3;\n        int b = (2 * n) / 3;\n        double x = rng.next_double();\n        if (x < 0.20) {\n            l = 0; r = max(0, a - 1);\n        } else if (x < 0.60) {\n            l = a; r = max(a, b - 1);\n        } else {\n            l = b; r = n - 1;\n        }\n    }\n    return bp[l + rng.next_int(0, r - l)];\n}\n\n// opening search\nvoid consider_open_leaf(int u, int accScore) {\n    int bt, bu;\n    best_future_from_current(u, bt, bu);\n    long long totalUB = (long long)accScore + bu;\n    int totalTiles = (int)openingCur.size() + bt;\n    if (totalUB > openingBestUB ||\n        (totalUB == openingBestUB && (totalTiles > openingBestTiles ||\n         (totalTiles == openingBestTiles && accScore > openingBestAcc)))) {\n        openingBestUB = totalUB;\n        openingBestTiles = totalTiles;\n        openingBestAcc = accScore;\n        openingBest = openingCur;\n    }\n}\n\nvoid opening_dfs(int u, int depthChoices, int accScore) {\n    if (openingTimeout) return;\n    if ((++openingNodes & 511) == 0) {\n        if (openingNodes >= OPENING_NODE_LIMIT || Clock::now() >= openingDeadline) {\n            openingTimeout = true;\n            return;\n        }\n    }\n\n    while (true) {\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n\n        if (ccnt == 0) {\n            consider_open_leaf(u, accScore);\n            return;\n        }\n\n        if (ccnt == 1) {\n            int v = cand[0];\n            usedTile[tileId[v]] = 1;\n            openingCur.push_back(v);\n            accScore += pval[v];\n            u = v;\n            continue;\n        }\n\n        int bt, bu;\n        best_future_from_current(u, bt, bu);\n        long long ubTotal = (long long)accScore + bu;\n        int tilesTotal = (int)openingCur.size() + bt;\n        if (ubTotal < openingBestUB ||\n            (ubTotal == openingBestUB && tilesTotal <= openingBestTiles)) {\n            return;\n        }\n\n        if (depthChoices == 0) {\n            consider_open_leaf(u, accScore);\n            return;\n        }\n\n        struct Ord {\n            int v, reachUb, reachTiles, altTiles, addScore;\n        };\n        Ord ord[4];\n        for (int i = 0; i < ccnt; ++i) {\n            MoveInfo mi;\n            preview_move_corridor(cand[i], mi);\n            ord[i] = {cand[i], mi.reachUb, mi.reachTiles, mi.altTiles, mi.addScore};\n        }\n\n        sort(ord, ord + ccnt, [](const Ord& a, const Ord& b) {\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n            return a.addScore > b.addScore;\n        });\n\n        for (int i = 0; i < ccnt; ++i) {\n            int trail[V];\n            int tcnt = 0;\n            int cur = ord[i].v;\n            int add = 0;\n\n            while (true) {\n                int tv = tileId[cur];\n                usedTile[tv] = 1;\n                trail[tcnt++] = cur;\n                openingCur.push_back(cur);\n                add += pval[cur];\n\n                int nexts[4];\n                int nc = avail_neighbors(cur, nexts);\n                if (nc != 1) break;\n                cur = nexts[0];\n            }\n\n            opening_dfs(cur, depthChoices - 1, accScore + add);\n\n            for (int j = 0; j < tcnt; ++j) usedTile[tileId[trail[j]]] = 0;\n            for (int j = 0; j < tcnt; ++j) openingCur.pop_back();\n\n            if (openingTimeout) return;\n        }\n        return;\n    }\n}\n\nstring to_answer(const vector<int>& pos) {\n    string ans;\n    ans.reserve(pos.size() > 0 ? pos.size() - 1 : 0);\n    for (size_t i = 1; i < pos.size(); ++i) {\n        int d = pos[i] - pos[i - 1];\n        if (d == -W) ans.push_back('U');\n        else if (d == W) ans.push_back('D');\n        else if (d == -1) ans.push_back('L');\n        else if (d == 1) ans.push_back('R');\n    }\n    return ans;\n}\n\nParams random_params(int mode) {\n    Params p;\n    if (mode == 2) { // elite suffix\n        p.style = (rng.next_double() < 0.28 ? 1 : 0);\n        if (p.style == 0) {\n            p.lookDepth = 5 + rng.next_int(0, 1);\n            p.tilesMargin = rng.next_int(0, 2);\n            p.ubMargin = rng.next_int(0, 90);\n            p.lookMargin = rng.next_int(0, 8);\n        } else {\n            p.lookDepth = 5 + rng.next_int(0, 1);\n            p.tilesMargin = 1 + rng.next_int(0, 2);\n            p.ubMargin = rng.next_int(0, 70);\n            p.lookMargin = rng.next_int(0, 7);\n        }\n    } else { // restart / opening prefix\n        p.style = (rng.next_double() < 0.35 ? 1 : 0);\n        if (p.style == 0) {\n            p.lookDepth = 6 + rng.next_int(0, 1);\n            p.tilesMargin = rng.next_int(0, 1);\n            p.ubMargin = rng.next_int(0, 70);\n            p.lookMargin = rng.next_int(0, 6);\n        } else {\n            p.lookDepth = 6 + rng.next_int(0, 1);\n            p.tilesMargin = 1 + rng.next_int(0, 1);\n            p.ubMargin = rng.next_int(0, 55);\n            p.lookMargin = rng.next_int(0, 5);\n        }\n    }\n    p.deterministic = false;\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj;\n    startIdx = id(si, sj);\n\n    int maxTile = -1;\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int t;\n            cin >> t;\n            tileId[id(i, j)] = t;\n            maxTile = max(maxTile, t);\n        }\n    }\n    M = maxTile + 1;\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            cin >> pval[id(i, j)];\n        }\n    }\n\n    tileMaxVal.assign(M, 0);\n    for (int v = 0; v < V; ++v) {\n        tileMaxVal[tileId[v]] = max(tileMaxVal[tileId[v]], pval[v]);\n    }\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int u = id(i, j);\n            int cnt = 0;\n            static const int di[4] = {-1, 1, 0, 0};\n            static const int dj[4] = {0, 0, -1, 1};\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 >= H || nj < 0 || nj >= W) continue;\n                int v = id(ni, nj);\n                if (tileId[v] == tileId[u]) continue;\n                adjList[u][cnt++] = v;\n            }\n            adjCnt[u] = (unsigned char)cnt;\n        }\n    }\n\n    usedTile.assign(M, 0);\n    tmpUsed.assign(M, 0);\n    visTile.assign(M, 0);\n    memset(visSq, 0, sizeof(visSq));\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)startIdx + 0x9e3779b97f4a7c15ull;\n    for (int v = 0; v < V; ++v) {\n        seed = seed * 1000003ull ^ (uint64_t)(tileId[v] + 1);\n        seed = seed * 1000003ull ^ (uint64_t)(pval[v] + 7);\n    }\n    rng.seed(seed);\n\n    globalDeadline = Clock::now() + chrono::milliseconds(1835);\n\n    // opening search\n    fill(usedTile.begin(), usedTile.end(), 0);\n    usedTile[tileId[startIdx]] = 1;\n\n    openingCur.clear();\n    openingBest.clear();\n    openingBestUB = -1;\n    openingBestTiles = -1;\n    openingBestAcc = -1;\n    openingTimeout = false;\n    openingNodes = 0;\n    openingDeadline = min(globalDeadline, Clock::now() + chrono::milliseconds(110));\n\n    opening_dfs(startIdx, 7, pval[startIdx]);\n\n    vector<int> openingPrefix;\n    openingPrefix.push_back(startIdx);\n    for (int v : openingBest) openingPrefix.push_back(v);\n\n    vector<Path> elites;\n\n    // baseline 1: opening prefix + deterministic safe\n    {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        int score = 0;\n        for (int v : openingPrefix) {\n            usedTile[tileId[v]] = 1;\n            score += pval[v];\n        }\n        Params safe;\n        safe.lookDepth = 7;\n        safe.tilesMargin = 0;\n        safe.ubMargin = 0;\n        safe.lookMargin = 0;\n        safe.deterministic = true;\n        safe.style = 0;\n        Path base = build_path(openingPrefix, score, safe, globalDeadline);\n        add_elite(elites, std::move(base));\n    }\n\n    // baseline 2: start only + deterministic safe\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        Params safe;\n        safe.lookDepth = 6;\n        safe.deterministic = true;\n        safe.style = 0;\n        Path base2 = build_path(vector<int>{startIdx}, pval[startIdx], safe, globalDeadline);\n        add_elite(elites, std::move(base2));\n    }\n\n    // baseline 3: start only + deterministic score-biased\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        Params agg;\n        agg.lookDepth = 6;\n        agg.tilesMargin = 1;\n        agg.ubMargin = 0;\n        agg.lookMargin = 0;\n        agg.deterministic = true;\n        agg.style = 1;\n        Path base3 = build_path(vector<int>{startIdx}, pval[startIdx], agg, globalDeadline);\n        add_elite(elites, std::move(base3));\n    }\n\n    // baseline 4: opening prefix + randomized\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        int score = 0;\n        for (int v : openingPrefix) {\n            usedTile[tileId[v]] = 1;\n            score += pval[v];\n        }\n        Params rp = random_params(1);\n        Path base4 = build_path(openingPrefix, score, rp, globalDeadline);\n        add_elite(elites, std::move(base4));\n    }\n\n    // baseline 5: start only + randomized\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        Params rp = random_params(0);\n        Path base5 = build_path(vector<int>{startIdx}, pval[startIdx], rp, globalDeadline);\n        add_elite(elites, std::move(base5));\n    }\n\n    while (Clock::now() < globalDeadline) {\n        int mode = 2; // 0:start, 1:opening prefix, 2:elite suffix\n        double x = rng.next_double();\n        if (elites.empty() || x < 0.26) mode = 0;\n        else if (x < 0.38 && openingPrefix.size() > 1) mode = 1;\n\n        fill(usedTile.begin(), usedTile.end(), 0);\n        vector<int> pref;\n        int score = 0;\n\n        if (mode == 0) {\n            pref = {startIdx};\n            usedTile[tileId[startIdx]] = 1;\n            score = pval[startIdx];\n        } else if (mode == 1) {\n            int n = (int)openingPrefix.size();\n            int len;\n            if (n <= 2) len = n;\n            else if (rng.next_double() < 0.50) len = n;\n            else len = rng.next_int(max(1, n / 2), n);\n            pref.assign(openingPrefix.begin(), openingPrefix.begin() + len);\n            for (int v : pref) {\n                usedTile[tileId[v]] = 1;\n                score += pval[v];\n            }\n        } else {\n            int ei = choose_elite(elites);\n            const Path& src = elites[ei];\n            if (src.branchPoints.empty()) {\n                pref = {startIdx};\n                usedTile[tileId[startIdx]] = 1;\n                score = pval[startIdx];\n            } else {\n                int cut = choose_cut(src);\n                pref.assign(src.pos.begin(), src.pos.begin() + cut + 1);\n                score = src.prefixScore[cut];\n                for (int i = 0; i <= cut; ++i) usedTile[tileId[src.pos[i]]] = 1;\n            }\n        }\n\n        Params prm = random_params(mode);\n        Path cand = build_path(std::move(pref), score, prm, globalDeadline);\n        add_elite(elites, std::move(cand));\n    }\n\n    if (elites.empty()) {\n        cout << '\\n';\n        return 0;\n    }\n\n    cout << to_answer(elites[0].pos) << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int HN = N * (N - 1);   // 870\nstatic constexpr int VN = (N - 1) * N;   // 870\nstatic constexpr int E = HN + VN;        // 1740\n\nstatic constexpr double INIT_COST = 5000.0;\nstatic constexpr double MIN_COST = 1000.0;\nstatic constexpr double MAX_COST = 9000.0;\n\ninline int hid(int i, int j) { return i * 29 + j; }          // (i,j) <-> (i,j+1)\ninline int vid(int i, int j) { return HN + i * 30 + j; }     // (i,j) <-> (i+1,j)\ninline int node_id(int i, int j) { return i * N + j; }\n\nstruct Path {\n    string s;\n    vector<int> edges;\n    double sumX = 0.0;\n    double sumPrior = 0.0;\n    double sumUnc = 0.0; // sum 1/sqrt(vis+1)\n};\n\nstruct Observation {\n    vector<int> edges;\n    array<uint8_t, 30> hcnt{};   // # horizontal edges used on each row\n    array<uint8_t, 30> vcnt{};   // # vertical edges used on each column\n    double y = 0.0;\n    double w = 0.0;\n    int len = 0;\n};\n\nstruct FitRes29 {\n    array<double, 29> out{};\n    bool use_two = false;\n    double improve = 0.0;\n    double diff = 0.0;\n};\n\nstruct Solver {\n    vector<double> x;       // current edge estimate\n    vector<double> prior;   // structured prior\n    vector<int> vis;\n    vector<Observation> hist;\n\n    array<double, 30> rowAvgH{};\n    array<double, 30> colAvgV{};\n\n    mt19937 rng;\n\n    Solver() : x(E, INIT_COST), prior(E, INIT_COST), vis(E, 0) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        for (int i = 0; i < 30; ++i) {\n            rowAvgH[i] = INIT_COST;\n            colAvgV[i] = INIT_COST;\n        }\n        hist.reserve(1000);\n    }\n\n    int randint(int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    static double clampd(double x, double lo, double hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    static double dot_vec(const vector<double>& a, const vector<double>& b) {\n        double s = 0.0;\n        for (int i = 0; i < (int)a.size(); ++i) s += a[i] * b[i];\n        return s;\n    }\n\n    inline double est_edge(int e) const {\n        return clampd(x[e], MIN_COST, MAX_COST);\n    }\n\n    inline double plan_edge(int e) const {\n        double conf = (double)vis[e] / ((double)vis[e] + 3.0);\n        return clampd((1.0 - conf) * prior[e] + conf * x[e], MIN_COST, MAX_COST);\n    }\n\n    inline double unc_edge(int e) const {\n        return 1.0 / sqrt((double)vis[e] + 1.0);\n    }\n\n    void finalize_path(Path& p) const {\n        p.sumX = p.sumPrior = p.sumUnc = 0.0;\n        for (int e : p.edges) {\n            p.sumX += est_edge(e);\n            p.sumPrior += prior[e];\n            p.sumUnc += unc_edge(e);\n        }\n    }\n\n    FitRes29 fit_piecewise_29(const array<double, 29>& val, const array<double, 29>& wt) const {\n        FitRes29 res;\n\n        array<double, 30> W{}, S{}, Q{};\n        for (int i = 0; i < 29; ++i) {\n            W[i + 1] = W[i] + wt[i];\n            S[i + 1] = S[i] + wt[i] * val[i];\n            Q[i + 1] = Q[i] + wt[i] * val[i] * val[i];\n        }\n\n        auto seg = [&](int l, int r) -> tuple<double, double, double> {\n            double w = W[r + 1] - W[l];\n            double s = S[r + 1] - S[l];\n            double q = Q[r + 1] - Q[l];\n            if (w < 1e-12) return {INIT_COST, 0.0, 0.0};\n            double m = s / w;\n            double err = q - s * s / w;\n            return {m, err, w};\n        };\n\n        auto [m1, e1, w1] = seg(0, 28);\n\n        double best2 = 1e100;\n        int bestk = -1;\n        double ml = m1, mr = m1;\n        for (int k = 1; k <= 28; ++k) {\n            auto [a, ea, wa] = seg(0, k - 1);\n            auto [b, eb, wb] = seg(k, 28);\n            double tot = ea + eb;\n            if (tot < best2) {\n                best2 = tot;\n                bestk = k;\n                ml = a;\n                mr = b;\n            }\n        }\n\n        res.diff = fabs(ml - mr);\n        if (e1 > 1e-9) res.improve = 1.0 - best2 / e1;\n        else res.improve = 0.0;\n\n        bool two = false;\n        if (bestk != -1 && e1 > 1e-9) {\n            if (best2 < e1 * 0.80 && fabs(ml - mr) > 220.0) {\n                two = true;\n            }\n        }\n        res.use_two = two;\n\n        if (!two) {\n            for (int i = 0; i < 29; ++i) res.out[i] = m1;\n        } else {\n            for (int i = 0; i < bestk; ++i) res.out[i] = ml;\n            for (int i = bestk; i < 29; ++i) res.out[i] = mr;\n        }\n\n        for (int i = 0; i < 29; ++i) {\n            res.out[i] = clampd(res.out[i], MIN_COST, MAX_COST);\n        }\n        return res;\n    }\n\n    Observation make_observation(const Path& path, double y) {\n        Observation ob;\n        ob.edges = path.edges;\n        ob.len = (int)path.edges.size();\n        ob.y = y;\n        ob.w = 1.0 / max(1, ob.len);\n\n        for (int e : path.edges) {\n            if (e < HN) {\n                int r = e / 29;\n                ob.hcnt[r]++;\n            } else {\n                int id = e - HN;\n                int c = id % 30;\n                ob.vcnt[c]++;\n            }\n        }\n        return ob;\n    }\n\n    void solve_coarse_model() {\n        if (hist.empty()) {\n            for (int i = 0; i < 30; ++i) {\n                rowAvgH[i] = INIT_COST;\n                colAvgV[i] = INIT_COST;\n            }\n            return;\n        }\n\n        static double A[60][61];\n        for (int i = 0; i < 60; ++i) {\n            for (int j = 0; j <= 60; ++j) A[i][j] = 0.0;\n        }\n\n        int nobs = (int)hist.size();\n        double lambda = 1.2 / sqrt((double)nobs + 1.0) + 0.12;\n\n        for (int p = 0; p < 60; ++p) {\n            A[p][p] += lambda;\n            A[p][60] += lambda * INIT_COST;\n        }\n\n        vector<pair<int, double>> feats;\n        feats.reserve(60);\n\n        for (const auto& ob : hist) {\n            feats.clear();\n            for (int r = 0; r < 30; ++r) if (ob.hcnt[r]) feats.push_back({r, (double)ob.hcnt[r]});\n            for (int c = 0; c < 30; ++c) if (ob.vcnt[c]) feats.push_back({30 + c, (double)ob.vcnt[c]});\n\n            double w = ob.w;\n            for (auto [i, vi] : feats) {\n                A[i][60] += w * vi * ob.y;\n            }\n            for (auto [i, vi] : feats) {\n                for (auto [j, vj] : feats) {\n                    A[i][j] += w * vi * vj;\n                }\n            }\n        }\n\n        for (int col = 0; col < 60; ++col) {\n            int pivot = col;\n            for (int r = col + 1; r < 60; ++r) {\n                if (fabs(A[r][col]) > fabs(A[pivot][col])) pivot = r;\n            }\n            if (fabs(A[pivot][col]) < 1e-12) continue;\n\n            if (pivot != col) {\n                for (int j = col; j <= 60; ++j) swap(A[pivot][j], A[col][j]);\n            }\n\n            double div = A[col][col];\n            for (int j = col; j <= 60; ++j) A[col][j] /= div;\n\n            for (int r = 0; r < 60; ++r) {\n                if (r == col) continue;\n                double fac = A[r][col];\n                if (fabs(fac) < 1e-12) continue;\n                for (int j = col; j <= 60; ++j) {\n                    A[r][j] -= fac * A[col][j];\n                }\n            }\n        }\n\n        for (int r = 0; r < 30; ++r) rowAvgH[r] = clampd(A[r][60], MIN_COST, MAX_COST);\n        for (int c = 0; c < 30; ++c) colAvgV[c] = clampd(A[30 + c][60], MIN_COST, MAX_COST);\n    }\n\n    void build_prior() {\n        solve_coarse_model();\n\n        for (int i = 0; i < 30; ++i) {\n            for (int j = 0; j < 29; ++j) prior[hid(i, j)] = rowAvgH[i];\n        }\n        for (int j = 0; j < 30; ++j) {\n            for (int i = 0; i < 29; ++i) prior[vid(i, j)] = colAvgV[j];\n        }\n\n        for (int i = 0; i < 30; ++i) {\n            int sumv = 0;\n            array<double, 29> val{}, wt{};\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                val[j] = x[e];\n                wt[j] = vis[e] + 2.0;\n                sumv += vis[e];\n            }\n            if (sumv < 12) continue;\n\n            auto fr = fit_piecewise_29(val, wt);\n            if (!fr.use_two || fr.improve < 0.20) continue;\n\n            double beta = 0.15 + 0.25 * ((double)sumv / ((double)sumv + 20.0));\n            beta = min(beta, 0.40);\n\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                prior[e] = clampd((1.0 - beta) * prior[e] + beta * fr.out[j], MIN_COST, MAX_COST);\n            }\n        }\n\n        for (int j = 0; j < 30; ++j) {\n            int sumv = 0;\n            array<double, 29> val{}, wt{};\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                val[i] = x[e];\n                wt[i] = vis[e] + 2.0;\n                sumv += vis[e];\n            }\n            if (sumv < 12) continue;\n\n            auto fr = fit_piecewise_29(val, wt);\n            if (!fr.use_two || fr.improve < 0.20) continue;\n\n            double beta = 0.15 + 0.25 * ((double)sumv / ((double)sumv + 20.0));\n            beta = min(beta, 0.40);\n\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                prior[e] = clampd((1.0 - beta) * prior[e] + beta * fr.out[i], MIN_COST, MAX_COST);\n            }\n        }\n    }\n\n    Path random_monotone_path(int si, int sj, int ti, int tj) {\n        Path p;\n        int i = si, j = sj;\n        int rv = abs(ti - si);\n        int rh = abs(tj - sj);\n        char mv_v = (ti > si ? 'D' : 'U');\n        char mv_h = (tj > sj ? 'R' : 'L');\n\n        p.s.reserve(rv + rh);\n        p.edges.reserve(rv + rh);\n\n        while (rv > 0 || rh > 0) {\n            bool take_v;\n            if (rv == 0) take_v = false;\n            else if (rh == 0) take_v = true;\n            else take_v = (randint(1, rv + rh) <= rv);\n\n            if (take_v) {\n                int e;\n                if (mv_v == 'D') {\n                    e = vid(i, j);\n                    ++i;\n                } else {\n                    e = vid(i - 1, j);\n                    --i;\n                }\n                p.s.push_back(mv_v);\n                p.edges.push_back(e);\n                --rv;\n            } else {\n                int e;\n                if (mv_h == 'R') {\n                    e = hid(i, j);\n                    ++j;\n                } else {\n                    e = hid(i, j - 1);\n                    --j;\n                }\n                p.s.push_back(mv_h);\n                p.edges.push_back(e);\n                --rh;\n            }\n        }\n        finalize_path(p);\n        return p;\n    }\n\n    Path ordered_monotone_path(int si, int sj, int ti, int tj, bool horiz_first) {\n        Path p;\n        int i = si, j = sj;\n        int rh = abs(tj - sj);\n        int rv = abs(ti - si);\n        char ch = (tj > sj ? 'R' : 'L');\n        char cv = (ti > si ? 'D' : 'U');\n\n        p.s.reserve(rh + rv);\n        p.edges.reserve(rh + rv);\n\n        auto step_h = [&](char c) {\n            int e;\n            if (c == 'R') {\n                e = hid(i, j);\n                ++j;\n            } else {\n                e = hid(i, j - 1);\n                --j;\n            }\n            p.s.push_back(c);\n            p.edges.push_back(e);\n        };\n\n        auto step_v = [&](char c) {\n            int e;\n            if (c == 'D') {\n                e = vid(i, j);\n                ++i;\n            } else {\n                e = vid(i - 1, j);\n                --i;\n            }\n            p.s.push_back(c);\n            p.edges.push_back(e);\n        };\n\n        if (horiz_first) {\n            while (rh--) step_h(ch);\n            while (rv--) step_v(cv);\n        } else {\n            while (rv--) step_v(cv);\n            while (rh--) step_h(ch);\n        }\n\n        finalize_path(p);\n        return p;\n    }\n\n    double search_cost_adaptive(int e, double ucoef) const {\n        return plan_edge(e) + ucoef * unc_edge(e);\n    }\n\n    double search_cost_fixedmix(int e, double lambda_x, double ucoef) const {\n        double c = lambda_x * est_edge(e) + (1.0 - lambda_x) * prior[e];\n        c = clampd(c, MIN_COST, MAX_COST);\n        return c + ucoef * unc_edge(e);\n    }\n\n    Path dijkstra_adaptive(int si, int sj, int ti, int tj, double step_penalty, double ucoef) const {\n        const int V = N * N;\n        const double INF = 1e100;\n\n        vector<double> dist(V, INF);\n        vector<int> parent(V, -1), parent_edge(V, -1);\n        vector<char> parent_char(V, '?');\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        int s = node_id(si, sj), t = node_id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        auto relax = [&](int v, int ni, int nj, int e, char c) {\n            int nv = node_id(ni, nj);\n            double nd = dist[v] + search_cost_adaptive(e, ucoef) + step_penalty;\n            if (nd + 1e-12 < dist[nv]) {\n                dist[nv] = nd;\n                parent[nv] = v;\n                parent_edge[nv] = e;\n                parent_char[nv] = c;\n                pq.push({nd, nv});\n            }\n        };\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d > dist[v] + 1e-12) continue;\n            if (v == t) break;\n\n            int i = v / N;\n            int j = v % N;\n\n            if (i > 0) relax(v, i - 1, j, vid(i - 1, j), 'U');\n            if (i + 1 < N) relax(v, i + 1, j, vid(i, j), 'D');\n            if (j > 0) relax(v, i, j - 1, hid(i, j - 1), 'L');\n            if (j + 1 < N) relax(v, i, j + 1, hid(i, j), 'R');\n        }\n\n        Path res;\n        vector<char> rs;\n        vector<int> re;\n\n        for (int cur = t; cur != s; cur = parent[cur]) {\n            rs.push_back(parent_char[cur]);\n            re.push_back(parent_edge[cur]);\n        }\n        reverse(rs.begin(), rs.end());\n        reverse(re.begin(), re.end());\n\n        res.s.assign(rs.begin(), rs.end());\n        res.edges = move(re);\n        finalize_path(res);\n        return res;\n    }\n\n    Path dijkstra_fixedmix(int si, int sj, int ti, int tj, double step_penalty, double lambda_x, double ucoef) const {\n        const int V = N * N;\n        const double INF = 1e100;\n\n        vector<double> dist(V, INF);\n        vector<int> parent(V, -1), parent_edge(V, -1);\n        vector<char> parent_char(V, '?');\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        int s = node_id(si, sj), t = node_id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        auto relax = [&](int v, int ni, int nj, int e, char c) {\n            int nv = node_id(ni, nj);\n            double nd = dist[v] + search_cost_fixedmix(e, lambda_x, ucoef) + step_penalty;\n            if (nd + 1e-12 < dist[nv]) {\n                dist[nv] = nd;\n                parent[nv] = v;\n                parent_edge[nv] = e;\n                parent_char[nv] = c;\n                pq.push({nd, nv});\n            }\n        };\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d > dist[v] + 1e-12) continue;\n            if (v == t) break;\n\n            int i = v / N;\n            int j = v % N;\n\n            if (i > 0) relax(v, i - 1, j, vid(i - 1, j), 'U');\n            if (i + 1 < N) relax(v, i + 1, j, vid(i, j), 'D');\n            if (j > 0) relax(v, i, j - 1, hid(i, j - 1), 'L');\n            if (j + 1 < N) relax(v, i, j + 1, hid(i, j), 'R');\n        }\n\n        Path res;\n        vector<char> rs;\n        vector<int> re;\n\n        for (int cur = t; cur != s; cur = parent[cur]) {\n            rs.push_back(parent_char[cur]);\n            re.push_back(parent_edge[cur]);\n        }\n        reverse(rs.begin(), rs.end());\n        reverse(re.begin(), re.end());\n\n        res.s.assign(rs.begin(), rs.end());\n        res.edges = move(re);\n        finalize_path(res);\n        return res;\n    }\n\n    double robust_score(const Path& p, int qidx, double explore_bonus) const {\n        double wx;\n        if (qidx < 100) wx = 0.40;\n        else if (qidx < 250) wx = 0.50;\n        else if (qidx < 600) wx = 0.62;\n        else wx = 0.74;\n        double wp = 1.0 - wx;\n\n        double ucoef;\n        if (qidx < 120) ucoef = 110.0;\n        else if (qidx < 350) ucoef = 70.0;\n        else ucoef = 35.0;\n\n        double sc = wx * p.sumX + wp * p.sumPrior + ucoef * p.sumUnc;\n        sc -= explore_bonus * p.sumUnc;\n        return sc;\n    }\n\n    Path choose_path(int si, int sj, int ti, int tj, int qidx) {\n        bool explore = false;\n        int samples = 0;\n        double bonus = 0.0;\n\n        if (qidx < 90) {\n            explore = true;\n            samples = 18;\n            bonus = 230.0;\n        } else if (qidx < 150) {\n            explore = true;\n            samples = 8;\n            bonus = 160.0;\n        } else if (qidx < 320 && rand01() < 0.04) {\n            explore = true;\n            samples = 4;\n            bonus = 90.0;\n        }\n\n        double base_step = 35.0;\n        if (qidx < 220) {\n            base_step += 250.0 * (220 - qidx) / 220.0;\n        }\n\n        double u_adapt = (qidx < 160 ? 70.0 : qidx < 450 ? 40.0 : 20.0);\n        double u_x     = (qidx < 160 ? 100.0 : qidx < 450 ? 50.0 : 20.0);\n        double u_prior = (qidx < 160 ? 35.0 : qidx < 450 ? 20.0 : 10.0);\n\n        vector<Path> cands;\n        cands.reserve(32);\n\n        cands.push_back(dijkstra_adaptive(si, sj, ti, tj, base_step, u_adapt));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 1.0, u_x));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 0.0, u_prior));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 0.5, u_adapt));\n        cands.push_back(ordered_monotone_path(si, sj, ti, tj, true));\n        cands.push_back(ordered_monotone_path(si, sj, ti, tj, false));\n\n        if (qidx < 220) {\n            cands.push_back(dijkstra_adaptive(si, sj, ti, tj, 0.0, u_adapt * 0.7));\n        }\n\n        if (explore) {\n            for (int t = 0; t < samples; ++t) {\n                cands.push_back(random_monotone_path(si, sj, ti, tj));\n            }\n        }\n\n        int best_id = 0;\n        double best_sc = robust_score(cands[0], qidx, explore ? bonus : 0.0);\n\n        for (int i = 1; i < (int)cands.size(); ++i) {\n            double sc = robust_score(cands[i], qidx, explore ? bonus : 0.0);\n            if (sc + 1e-12 < best_sc) {\n                best_sc = sc;\n                best_id = i;\n            } else if (fabs(sc - best_sc) < 1e-12) {\n                if (cands[i].edges.size() < cands[best_id].edges.size()) best_id = i;\n            }\n        }\n        return cands[best_id];\n    }\n\n    void online_update(const Path& path, double y, int qidx) {\n        int m = (int)path.edges.size();\n        if (m == 0) return;\n\n        double pred = path.sumX;\n        double residual = y - pred;\n\n        double eta;\n        if (qidx < 120) eta = 0.30;\n        else if (qidx < 350) eta = 0.22;\n        else eta = 0.16;\n\n        vector<double> u(m);\n        double su = 0.0;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            u[k] = 1.0 / sqrt((double)vis[e] + 1.0);\n            su += u[k];\n        }\n        if (su < 1e-12) su = 1.0;\n\n        double scale = eta * residual / su;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            double delta = scale * u[k];\n            delta = clampd(delta, -900.0, 900.0);\n            x[e] = clampd(x[e] + delta, MIN_COST, MAX_COST);\n        }\n\n        for (int e : path.edges) vis[e]++;\n        hist.push_back(make_observation(path, y));\n    }\n\n    void global_refine() {\n        int nobs = (int)hist.size();\n        if (nobs == 0) return;\n\n        build_prior();\n\n        double lambda0 = 0.10 / sqrt((double)nobs + 1.0) + 0.020;\n        double lambda1 = 0.32 / sqrt((double)nobs + 1.0) + 0.035;\n\n        vector<double> alpha(E), rhs(E, 0.0);\n        for (int e = 0; e < E; ++e) {\n            alpha[e] = 1.0 / sqrt((double)vis[e] + 1.0);\n            rhs[e] = lambda0 * alpha[e] * prior[e];\n        }\n\n        for (const auto& ob : hist) {\n            double c = ob.w * ob.y;\n            for (int e : ob.edges) rhs[e] += c;\n        }\n\n        auto apply = [&](const vector<double>& p, vector<double>& out) {\n            out.assign(E, 0.0);\n\n            for (int e = 0; e < E; ++e) {\n                out[e] = lambda0 * alpha[e] * p[e];\n            }\n\n            for (const auto& ob : hist) {\n                double s = 0.0;\n                for (int e : ob.edges) s += p[e];\n                s *= ob.w;\n                for (int e : ob.edges) out[e] += s;\n            }\n\n            for (int i = 0; i < 30; ++i) {\n                for (int j = 0; j < 28; ++j) {\n                    int e1 = hid(i, j);\n                    int e2 = hid(i, j + 1);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n\n            for (int j = 0; j < 30; ++j) {\n                for (int i = 0; i < 28; ++i) {\n                    int e1 = vid(i, j);\n                    int e2 = vid(i + 1, j);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n        };\n\n        vector<double> sol = x, r(E), p(E), Ap(E);\n        apply(sol, Ap);\n        for (int e = 0; e < E; ++e) r[e] = rhs[e] - Ap[e];\n        p = r;\n\n        double rs0 = dot_vec(r, r);\n        double rs = rs0;\n        if (rs < 1e-12) return;\n\n        const int ITERS = 28;\n        for (int it = 0; it < ITERS; ++it) {\n            apply(p, Ap);\n            double pAp = dot_vec(p, Ap);\n            if (pAp <= 1e-18) break;\n\n            double a = rs / pAp;\n            for (int e = 0; e < E; ++e) sol[e] += a * p[e];\n            for (int e = 0; e < E; ++e) r[e] -= a * Ap[e];\n\n            double rs_new = dot_vec(r, r);\n            if (rs_new < rs0 * 1e-10) break;\n\n            double b = rs_new / rs;\n            for (int e = 0; e < E; ++e) p[e] = r[e] + b * p[e];\n            rs = rs_new;\n        }\n\n        for (int e = 0; e < E; ++e) {\n            x[e] = clampd(sol[e], MIN_COST, MAX_COST);\n        }\n\n        for (int e = 0; e < E; ++e) {\n            double g = 0.10 / sqrt((double)vis[e] + 1.0);\n            x[e] = clampd((1.0 - g) * x[e] + g * prior[e], MIN_COST, MAX_COST);\n        }\n\n        build_prior();\n    }\n\n    bool should_refine(int qq) const {\n        if (qq <= 160) return qq % 20 == 0;\n        if (qq <= 400) return qq % 40 == 0;\n        return qq % 50 == 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        Path path = solver.choose_path(si, sj, ti, tj, q);\n\n        cout << path.s << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.online_update(path, (double)result, q);\n\n        int qq = q + 1;\n        if (solver.should_refine(qq)) {\n            solver.global_refine();\n        }\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nusing Matrix = array<unsigned char, N * N>;\n\nstruct Candidate {\n    string row;\n    vector<int> cover;\n    int totalWeight = 0;\n};\n\nstruct Move {\n    long long val;\n    string s;\n};\n\nstruct Edge {\n    int pid;\n    unsigned char req;\n};\n\nstruct StartResult {\n    long long score;\n    Matrix mat;\n};\n\nstruct RowState {\n    array<int, N> ord{};\n    array<int, N> sh{};\n    long long sc = LLONG_MIN;\n};\n\nstruct CellChange {\n    int cell;\n    unsigned char oldc;\n    unsigned char newc;\n};\n\nstatic chrono::steady_clock::time_point gStart;\nstatic inline long long elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - gStart\n    ).count();\n}\n\nmt19937 rng((unsigned)chrono::steady_clock::now().time_since_epoch().count());\n\n// compressed input\nvector<string> pats;\nvector<vector<unsigned char>> pch;\nvector<int> wt;\nvector<int> impOrder;\n\n// exact local search graph (all placements)\nvector<vector<Edge>> cellEdges; // 400 cells\nvector<int> plSid;\nvector<unsigned char> plLen;\nvector<unsigned char> plMatch;\n\n// vertical-only graph for zero-cost row operations\nvector<vector<Edge>> vCellEdges; // 400 cells\nvector<int> vPlSid;\nvector<unsigned char> vPlLen;\nvector<unsigned char> vPlMatch;\n\n// n-gram weights\nlong long pairW[8][8];\nlong long triW[8][8][8];\n\n// ---------------- row candidate generation utilities ----------------\n\ninline bool contains_in_doubled(const char* dd, const string& p) {\n    const int k = (int)p.size();\n    const char* ps = p.data();\n    for (int st = 0; st < N; ++st) {\n        int j = 0;\n        while (j < k && dd[st + j] == ps[j]) ++j;\n        if (j == k) return true;\n    }\n    return false;\n}\n\nint overlap_suffix_prefix(const string& a, const string& b) {\n    int lim = min((int)a.size(), (int)b.size());\n    for (int o = lim; o >= 1; --o) {\n        bool ok = true;\n        int sa = (int)a.size() - o;\n        for (int i = 0; i < o; ++i) {\n            if (a[sa + i] != b[i]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) return o;\n    }\n    return 0;\n}\n\nstring repeat_to_20(const string& s) {\n    if ((int)s.size() == N) return s;\n    string r(N, 'A');\n    for (int i = 0; i < N; ++i) r[i] = s[i % (int)s.size()];\n    return r;\n}\n\nstring min_rotation(const string& s) {\n    string best = s;\n    for (int sh = 1; sh < N; ++sh) {\n        string t = s.substr(sh) + s.substr(0, sh);\n        if (t < best) best = t;\n    }\n    return best;\n}\n\nvoid push_top(vector<Move>& top, long long val, const string& s, int cap = 4) {\n    if (val <= 0) return;\n    top.push_back({val, s});\n    int pos = (int)top.size() - 1;\n    while (pos > 0 && top[pos].val > top[pos - 1].val) {\n        swap(top[pos], top[pos - 1]);\n        --pos;\n    }\n    if ((int)top.size() > cap) top.pop_back();\n}\n\nstring choose_move(const vector<Move>& top, bool randomized) {\n    if (top.empty()) return \"\";\n    if (!randomized || top.size() == 1) return top[0].s;\n    int k = min<int>(3, top.size());\n    int r = (int)(rng() % 10);\n    int idx = 0;\n    if (k >= 3) {\n        if (r < 6) idx = 0;\n        else if (r < 9) idx = 1;\n        else idx = 2;\n    } else if (k == 2) {\n        idx = (r < 7 ? 0 : 1);\n    }\n    return top[idx].s;\n}\n\nstring build_candidate_row(int seedId, bool randomized) {\n    string cur = pats[seedId];\n    int scanLim = min<int>((int)impOrder.size(), 240);\n\n    // phase 0: strong overlap / containment\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            if ((int)x.size() > (int)cur.size()) {\n                if (x.find(cur) != string::npos && (int)x.size() <= N) {\n                    long long val = 1LL * wt[id] * 3000 + 1LL * ((int)x.size() - (int)cur.size()) * 200;\n                    push_top(top, val, x);\n                }\n            }\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty()) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    // phase 1: pack more strings\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty() || top[0].val <= 0) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    return repeat_to_20(cur);\n}\n\nvector<string> build_initial_rows(const vector<int>& charFreq) {\n    int U = (int)pats.size();\n    vector<Candidate> cands;\n    cands.reserve(400);\n\n    unordered_set<string> seen;\n    seen.reserve(2048);\n\n    auto add_candidate = [&](string row) {\n        if ((int)row.size() != N) row = repeat_to_20(row);\n        row = min_rotation(row);\n        if (!seen.insert(row).second) return;\n\n        char dd[40];\n        for (int i = 0; i < N; ++i) dd[i] = dd[i + N] = row[i];\n\n        Candidate cand;\n        cand.row = row;\n        cand.totalWeight = 0;\n        for (int id = 0; id < U; ++id) {\n            if (contains_in_doubled(dd, pats[id])) {\n                cand.cover.push_back(id);\n                cand.totalWeight += wt[id];\n            }\n        }\n        if (!cand.cover.empty()) cands.push_back(std::move(cand));\n    };\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n\n    for (int c = 0; c < 8; ++c) add_candidate(string(N, char('A' + c)));\n\n    for (int t = 0; t < min(U, 70); ++t) {\n        add_candidate(repeat_to_20(pats[impOrder[t]]));\n    }\n\n    for (int t = 0; t < min(U, 90); ++t) {\n        add_candidate(build_candidate_row(impOrder[t], false));\n        if (elapsed_ms() > 500) break;\n    }\n\n    for (int t = 0; t < 50; ++t) {\n        int lim = min(U, max(1, 40 + t * 2));\n        int seedId = impOrder[(int)(rng() % lim)];\n        add_candidate(build_candidate_row(seedId, true));\n        if (elapsed_ms() > 700) break;\n    }\n\n    if ((int)cands.size() < 20) {\n        for (int a = 0; a < 8; ++a) {\n            for (int b = 0; b < 8; ++b) {\n                string s(N, 'A');\n                for (int i = 0; i < N; ++i) s[i] = char('A' + ((i & 1) ? b : a));\n                add_candidate(s);\n                if ((int)cands.size() >= 20) break;\n            }\n            if ((int)cands.size() >= 20) break;\n        }\n    }\n\n    if (cands.empty()) {\n        vector<string> rows(20, string(N, char('A' + bestChar)));\n        return rows;\n    }\n\n    int C = (int)cands.size();\n\n    vector<int> selected;\n    selected.reserve(20);\n    vector<char> usedCand(C, 0);\n    vector<char> covered(U, 0);\n\n    for (int step = 0; step < 20 && step < C; ++step) {\n        int best = -1;\n        long long bestGain = -1;\n        int bestTotal = -1;\n        for (int ci = 0; ci < C; ++ci) if (!usedCand[ci]) {\n            long long gain = 0;\n            for (int id : cands[ci].cover) if (!covered[id]) gain += wt[id];\n            if (gain > bestGain || (gain == bestGain && cands[ci].totalWeight > bestTotal)) {\n                bestGain = gain;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n        if (best == -1) break;\n        usedCand[best] = 1;\n        selected.push_back(best);\n        for (int id : cands[best].cover) covered[id] = 1;\n    }\n\n    if ((int)selected.size() < 20) {\n        vector<int> ord(C);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return cands[a].totalWeight > cands[b].totalWeight;\n        });\n        for (int ci : ord) {\n            if ((int)selected.size() >= 20) break;\n            if (!usedCand[ci]) {\n                usedCand[ci] = 1;\n                selected.push_back(ci);\n            }\n        }\n    }\n    while ((int)selected.size() < 20) selected.push_back(selected[0]);\n\n    vector<int> coverCnt(U, 0);\n    long long rowWeight = 0;\n    fill(usedCand.begin(), usedCand.end(), 0);\n    for (int ci : selected) usedCand[ci] = 1;\n    for (int ci : selected) {\n        for (int id : cands[ci].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    for (int pos = 0; pos < 20; ++pos) {\n        int old = selected[pos];\n        usedCand[old] = 0;\n        for (int id : cands[old].cover) {\n            if (--coverCnt[id] == 0) rowWeight -= wt[id];\n        }\n\n        int best = old;\n        long long bestScore = rowWeight;\n        int bestTotal = cands[old].totalWeight;\n\n        for (int ci = 0; ci < C; ++ci) {\n            if (usedCand[ci]) continue;\n            long long sc = rowWeight;\n            for (int id : cands[ci].cover) {\n                if (coverCnt[id] == 0) sc += wt[id];\n            }\n            if (sc > bestScore || (sc == bestScore && cands[ci].totalWeight > bestTotal)) {\n                bestScore = sc;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n\n        selected[pos] = best;\n        usedCand[best] = 1;\n        for (int id : cands[best].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    vector<string> rows(20);\n    for (int i = 0; i < 20; ++i) rows[i] = cands[selected[i]].row;\n    return rows;\n}\n\n// ---------------- exact graph ----------------\n\nvoid build_exact_graph() {\n    int U = (int)pats.size();\n\n    cellEdges.assign(N * N, {});\n    vCellEdges.assign(N * N, {});\n\n    long long totalEdgesAll = 0;\n    long long totalEdgesV = 0;\n    for (int sid = 0; sid < U; ++sid) {\n        totalEdgesAll += 800LL * (int)pats[sid].size();\n        totalEdgesV += 400LL * (int)pats[sid].size();\n    }\n\n    int reserveAll = (int)(totalEdgesAll / (N * N)) + 64;\n    int reserveV = (int)(totalEdgesV / (N * N)) + 32;\n    for (int c = 0; c < N * N; ++c) {\n        cellEdges[c].reserve(reserveAll);\n        vCellEdges[c].reserve(reserveV);\n    }\n\n    plSid.clear();\n    plLen.clear();\n    plMatch.clear();\n    plSid.reserve(U * 800);\n    plLen.reserve(U * 800);\n    plMatch.reserve(U * 800);\n\n    vPlSid.clear();\n    vPlLen.clear();\n    vPlMatch.clear();\n    vPlSid.reserve(U * 400);\n    vPlLen.reserve(U * 400);\n    vPlMatch.reserve(U * 400);\n\n    for (int sid = 0; sid < U; ++sid) {\n        const auto& s = pch[sid];\n        int k = (int)s.size();\n\n        // horizontal placements\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n\n                int base = r * N;\n                for (int t = 0; t < k; ++t) {\n                    int cell = base + ((c + t) % N);\n                    cellEdges[cell].push_back({pid, s[t]});\n                }\n            }\n        }\n\n        // vertical placements\n        for (int c = 0; c < N; ++c) {\n            for (int r = 0; r < N; ++r) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n\n                int vpid = (int)vPlSid.size();\n                vPlSid.push_back(sid);\n                vPlLen.push_back((unsigned char)k);\n                vPlMatch.push_back(0);\n\n                for (int t = 0; t < k; ++t) {\n                    int cell = ((r + t) % N) * N + c;\n                    cellEdges[cell].push_back({pid, s[t]});\n                    vCellEdges[cell].push_back({vpid, s[t]});\n                }\n            }\n        }\n    }\n}\n\nlong long init_state(const Matrix& mat, vector<int>& fullCnt) {\n    fill(plMatch.begin(), plMatch.end(), 0);\n    for (int cell = 0; cell < N * N; ++cell) {\n        unsigned char ch = mat[cell];\n        for (const auto& e : cellEdges[cell]) {\n            if (e.req == ch) ++plMatch[e.pid];\n        }\n    }\n\n    fullCnt.assign(pats.size(), 0);\n    for (int pid = 0, P = (int)plSid.size(); pid < P; ++pid) {\n        if (plMatch[pid] == plLen[pid]) ++fullCnt[plSid[pid]];\n    }\n\n    long long score = 0;\n    for (int sid = 0; sid < (int)pats.size(); ++sid) {\n        if (fullCnt[sid] > 0) score += wt[sid];\n    }\n    return score;\n}\n\nvoid init_vertical_state(const Matrix& mat) {\n    fill(vPlMatch.begin(), vPlMatch.end(), 0);\n    for (int cell = 0; cell < N * N; ++cell) {\n        unsigned char ch = mat[cell];\n        for (const auto& e : vCellEdges[cell]) {\n            if (e.req == ch) ++vPlMatch[e.pid];\n        }\n    }\n}\n\n// ---------------- matrix utilities ----------------\n\nMatrix transpose_matrix(const Matrix& a) {\n    Matrix b{};\n    for (int r = 0; r < N; ++r)\n        for (int c = 0; c < N; ++c)\n            b[c * N + r] = a[r * N + c];\n    return b;\n}\n\nMatrix make_matrix_from_rows(const vector<string>& rows, bool randomizeOrderShift, bool doTranspose) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    if (randomizeOrderShift) shuffle(ord.begin(), ord.end(), rng);\n\n    Matrix mat{};\n    for (int r = 0; r < N; ++r) {\n        const string& s = rows[ord[r]];\n        int sh = randomizeOrderShift ? (int)(rng() % N) : 0;\n        for (int c = 0; c < N; ++c) mat[r * N + c] = (unsigned char)(s[(c + sh) % N] - 'A');\n    }\n    if (doTranspose) mat = transpose_matrix(mat);\n    return mat;\n}\n\nMatrix make_constant_matrix(int ch) {\n    Matrix mat{};\n    for (int i = 0; i < N * N; ++i) mat[i] = (unsigned char)ch;\n    return mat;\n}\n\nMatrix make_random_freq_matrix(const vector<int>& charFreq) {\n    array<int, 8> pref{};\n    pref[0] = charFreq[0];\n    for (int i = 1; i < 8; ++i) pref[i] = pref[i - 1] + charFreq[i];\n    int total = pref[7];\n    Matrix mat{};\n    for (int i = 0; i < N * N; ++i) {\n        int x = (int)(rng() % total);\n        int ch = 0;\n        while (pref[ch] <= x) ++ch;\n        mat[i] = (unsigned char)ch;\n    }\n    return mat;\n}\n\nvector<string> extract_rows(const Matrix& mat) {\n    vector<string> rows(N, string(N, 'A'));\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) rows[r][c] = char('A' + mat[r * N + c]);\n    }\n    return rows;\n}\n\n// ---------------- row order / shift optimization by n-grams ----------------\n\nvector<Matrix> build_ngram_starts(const vector<string>& rows) {\n    unsigned char rowChars[N][N][N];\n    for (int r = 0; r < N; ++r) {\n        for (int sh = 0; sh < N; ++sh) {\n            for (int c = 0; c < N; ++c) {\n                rowChars[r][sh][c] = (unsigned char)(rows[r][(c + sh) % N] - 'A');\n            }\n        }\n    }\n\n    auto totalScore = [&](const array<int, N>& ord, const array<int, N>& sh) -> long long {\n        long long sc = 0;\n        for (int p = 0; p < N; ++p) {\n            int a = ord[p];\n            int b = ord[(p + 1) % N];\n            int c = ord[(p + 2) % N];\n            int sa = sh[p];\n            int sb = sh[(p + 1) % N];\n            int scv = sh[(p + 2) % N];\n            for (int col = 0; col < N; ++col) {\n                unsigned char x = rowChars[a][sa][col];\n                unsigned char y = rowChars[b][sb][col];\n                unsigned char z = rowChars[c][scv][col];\n                sc += pairW[x][y];\n                sc += 2LL * triW[x][y][z];\n            }\n        }\n        return sc;\n    };\n\n    auto optimize_state = [&](RowState st) -> RowState {\n        st.sc = totalScore(st.ord, st.sh);\n\n        for (int it = 0; it < 8; ++it) {\n            bool improved = false;\n\n            // shifts\n            for (int p = 0; p < N; ++p) {\n                int bestSh = st.sh[p];\n                long long bestSc = st.sc;\n                int old = st.sh[p];\n                for (int cand = 0; cand < N; ++cand) {\n                    st.sh[p] = cand;\n                    long long sc = totalScore(st.ord, st.sh);\n                    if (sc > bestSc) {\n                        bestSc = sc;\n                        bestSh = cand;\n                    }\n                }\n                st.sh[p] = bestSh;\n                if (bestSc > st.sc) {\n                    st.sc = bestSc;\n                    improved = true;\n                } else {\n                    st.sh[p] = old;\n                }\n            }\n\n            // swaps\n            while (true) {\n                int bi = -1, bj = -1;\n                long long bestSc = st.sc;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = i + 1; j < N; ++j) {\n                        swap(st.ord[i], st.ord[j]);\n                        swap(st.sh[i], st.sh[j]);\n                        long long sc = totalScore(st.ord, st.sh);\n                        swap(st.ord[i], st.ord[j]);\n                        swap(st.sh[i], st.sh[j]);\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                swap(st.ord[bi], st.ord[bj]);\n                swap(st.sh[bi], st.sh[bj]);\n                st.sc = bestSc;\n                improved = true;\n            }\n\n            // insertions\n            while (true) {\n                int bi = -1, bj = -1;\n                long long bestSc = st.sc;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = 0; j < N; ++j) {\n                        if (i == j) continue;\n                        RowState tmp = st;\n                        int ro = tmp.ord[i], rs = tmp.sh[i];\n                        if (i < j) {\n                            for (int t = i; t < j; ++t) {\n                                tmp.ord[t] = tmp.ord[t + 1];\n                                tmp.sh[t] = tmp.sh[t + 1];\n                            }\n                            tmp.ord[j] = ro;\n                            tmp.sh[j] = rs;\n                        } else {\n                            for (int t = i; t > j; --t) {\n                                tmp.ord[t] = tmp.ord[t - 1];\n                                tmp.sh[t] = tmp.sh[t - 1];\n                            }\n                            tmp.ord[j] = ro;\n                            tmp.sh[j] = rs;\n                        }\n                        long long sc = totalScore(tmp.ord, tmp.sh);\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                int ro = st.ord[bi], rs = st.sh[bi];\n                if (bi < bj) {\n                    for (int t = bi; t < bj; ++t) {\n                        st.ord[t] = st.ord[t + 1];\n                        st.sh[t] = st.sh[t + 1];\n                    }\n                    st.ord[bj] = ro;\n                    st.sh[bj] = rs;\n                } else {\n                    for (int t = bi; t > bj; --t) {\n                        st.ord[t] = st.ord[t - 1];\n                        st.sh[t] = st.sh[t - 1];\n                    }\n                    st.ord[bj] = ro;\n                    st.sh[bj] = rs;\n                }\n                st.sc = bestSc;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return st;\n    };\n\n    vector<RowState> states;\n    auto make_state = [&](bool randOrd, bool randSh) {\n        RowState st;\n        for (int i = 0; i < N; ++i) st.ord[i] = i;\n        if (randOrd) shuffle(st.ord.begin(), st.ord.end(), rng);\n        for (int i = 0; i < N; ++i) st.sh[i] = randSh ? (int)(rng() % N) : 0;\n        return optimize_state(st);\n    };\n\n    states.push_back(make_state(false, false));\n    states.push_back(make_state(false, true));\n    states.push_back(make_state(true, false));\n    for (int t = 0; t < 4; ++t) states.push_back(make_state(true, true));\n\n    sort(states.begin(), states.end(), [&](const RowState& a, const RowState& b) {\n        return a.sc > b.sc;\n    });\n\n    auto state_to_matrix = [&](const RowState& st, bool transposed) {\n        Matrix mat{};\n        for (int r = 0; r < N; ++r) {\n            int rowId = st.ord[r];\n            int sh = st.sh[r];\n            for (int c = 0; c < N; ++c) {\n                mat[r * N + c] = rowChars[rowId][sh][c];\n            }\n        }\n        if (transposed) mat = transpose_matrix(mat);\n        return mat;\n    };\n\n    vector<Matrix> starts;\n    int lim = min<int>(4, states.size());\n    for (int i = 0; i < lim; ++i) {\n        starts.push_back(state_to_matrix(states[i], false));\n        starts.push_back(state_to_matrix(states[i], true));\n    }\n    return starts;\n}\n\n// ---------------- soft refinement ----------------\n\nStartResult soft_refine(Matrix mat, const vector<int>& kinds, const vector<int>& inertias, long long deadlineMs) {\n    vector<int> tmpFull;\n    StartResult best{init_state(mat, tmpFull), mat};\n\n    for (int pi = 0; pi < (int)kinds.size(); ++pi) {\n        if (elapsed_ms() > deadlineMs) break;\n\n        int kind = kinds[pi];\n        int inertia = inertias[pi];\n\n        long long votes[N * N][8];\n        memset(votes, 0, sizeof(votes));\n\n        for (int cell = 0; cell < N * N; ++cell) votes[cell][mat[cell]] += inertia;\n\n        unsigned char row2[N][2 * N];\n        unsigned char col2[N][2 * N];\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < 2 * N; ++c)\n                row2[r][c] = mat[r * N + (c % N)];\n        for (int c = 0; c < N; ++c)\n            for (int r = 0; r < 2 * N; ++r)\n                col2[c][r] = mat[(r % N) * N + c];\n\n        for (int sid = 0; sid < (int)pats.size(); ++sid) {\n            const auto& s = pch[sid];\n            int k = (int)s.size();\n\n            unsigned char scs[800];\n            int idx = 0;\n            int bestSc = -1;\n\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (row2[r][c + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n            for (int c = 0; c < N; ++c) {\n                for (int r = 0; r < N; ++r) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (col2[c][r + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n\n            int req, band;\n            long long base0, base1, base2;\n\n            if (kind == 0) {\n                req = max(3, (k + 1) / 2);\n                band = 0;\n                base0 = 64; base1 = 0; base2 = 0;\n            } else if (kind == 1) {\n                req = max(3, k / 2);\n                band = 1;\n                base0 = 48; base1 = 10; base2 = 0;\n            } else if (kind == 2) {\n                req = max(2, (k - 1) / 2);\n                band = 1;\n                base0 = 40; base1 = 14; base2 = 0;\n            } else if (kind == 3) {\n                req = 2;\n                band = 2;\n                base0 = 32; base1 = 12; base2 = 4;\n            } else if (kind == 4) {\n                req = max(2, k / 3);\n                band = 2;\n                base0 = 28; base1 = 12; base2 = 4;\n            } else {\n                req = 2;\n                band = 2;\n                base0 = 20; base1 = 10; base2 = 5;\n            }\n\n            if (bestSc < req) continue;\n\n            const int cap0 = 6, cap1 = 4, cap2 = 2;\n            int sel0[cap0], sel1[cap1], sel2[cap2];\n            int n0 = 0, n1 = 0, n2 = 0;\n            int seen0 = 0, seen1 = 0, seen2 = 0;\n\n            auto reservoir_add = [&](int* arr, int& n, int cap, int& seen, int code) {\n                ++seen;\n                if (n < cap) {\n                    arr[n++] = code;\n                } else {\n                    int r = (int)(rng() % seen);\n                    if (r < cap) arr[r] = code;\n                }\n            };\n\n            for (int code = 0; code < 800; ++code) {\n                int d = bestSc - (int)scs[code];\n                if (d == 0) reservoir_add(sel0, n0, cap0, seen0, code);\n                else if (d == 1 && band >= 1) reservoir_add(sel1, n1, cap1, seen1, code);\n                else if (d == 2 && band >= 2) reservoir_add(sel2, n2, cap2, seen2, code);\n            }\n\n            long long total0 = 1LL * wt[sid] * k * base0;\n            long long total1 = 1LL * wt[sid] * k * base1;\n            long long total2 = 1LL * wt[sid] * k * base2;\n\n            auto add_code = [&](int code, long long w) {\n                if (w <= 0) return;\n                if (code < 400) {\n                    int r = code / N;\n                    int c = code % N;\n                    int base = r * N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = base + ((c + t) % N);\n                        votes[cell][s[t]] += w;\n                    }\n                } else {\n                    int x = code - 400;\n                    int c = x / N;\n                    int r = x % N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = ((r + t) % N) * N + c;\n                        votes[cell][s[t]] += w;\n                    }\n                }\n            };\n\n            if (n0 > 0) {\n                long long w = total0 / n0;\n                for (int i = 0; i < n0; ++i) add_code(sel0[i], w);\n            }\n            if (n1 > 0) {\n                long long w = total1 / n1;\n                for (int i = 0; i < n1; ++i) add_code(sel1[i], w);\n            }\n            if (n2 > 0) {\n                long long w = total2 / n2;\n                for (int i = 0; i < n2; ++i) add_code(sel2[i], w);\n            }\n        }\n\n        int changes = 0;\n        for (int cell = 0; cell < N * N; ++cell) {\n            unsigned char old = mat[cell];\n            unsigned char bestCh = old;\n            long long bestV = votes[cell][old];\n            for (unsigned char ch = 0; ch < 8; ++ch) {\n                if (votes[cell][ch] > bestV) {\n                    bestV = votes[cell][ch];\n                    bestCh = ch;\n                }\n            }\n            if (bestCh != old) {\n                mat[cell] = bestCh;\n                ++changes;\n            }\n        }\n\n        long long sc = init_state(mat, tmpFull);\n        if (sc > best.score) best = {sc, mat};\n        if (changes == 0) break;\n    }\n\n    return best;\n}\n\n// ---------------- exact hill-climb ----------------\n\nStartResult exact_hillclimb(Matrix mat, int maxPass, long long endMs) {\n    vector<int> fullCnt;\n    long long curScore = init_state(mat, fullCnt);\n    StartResult best{curScore, mat};\n\n    vector<int> order(N * N);\n    iota(order.begin(), order.end(), 0);\n\n    int U = (int)pats.size();\n    vector<int> seen(U, 0), inc(U, 0), dec(U, 0), touched;\n    touched.reserve(U);\n    int stamp = 1;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        if (elapsed_ms() > endMs) break;\n        shuffle(order.begin(), order.end(), rng);\n        bool improved = false;\n\n        for (int cell : order) {\n            if (elapsed_ms() > endMs) break;\n\n            unsigned char old = mat[cell];\n            long long bestDelta = 0;\n            unsigned char bestCh = old;\n\n            for (unsigned char nw = 0; nw < 8; ++nw) {\n                if (nw == old) continue;\n                ++stamp;\n                touched.clear();\n\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == nw);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n\n                    if (seen[sid] != stamp) {\n                        seen[sid] = stamp;\n                        inc[sid] = 0;\n                        dec[sid] = 0;\n                        touched.push_back(sid);\n                    }\n\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) ++dec[sid];\n                    } else {\n                        if ((int)plMatch[pid] + 1 == (int)plLen[pid]) ++inc[sid];\n                    }\n                }\n\n                long long delta = 0;\n                for (int sid : touched) {\n                    int oldCnt = fullCnt[sid];\n                    int newCnt = oldCnt - dec[sid] + inc[sid];\n                    if (oldCnt == 0 && newCnt > 0) delta += wt[sid];\n                    else if (oldCnt > 0 && newCnt == 0) delta -= wt[sid];\n                }\n\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestCh = nw;\n                }\n            }\n\n            if (bestCh != old) {\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == bestCh);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) --fullCnt[sid];\n                        --plMatch[pid];\n                    } else {\n                        ++plMatch[pid];\n                        if (plMatch[pid] == plLen[pid]) ++fullCnt[sid];\n                    }\n                }\n                mat[cell] = bestCh;\n                curScore += bestDelta;\n                improved = true;\n                if (curScore > best.score) best = {curScore, mat};\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return best;\n}\n\n// ---------------- exact zero-cost row optimizer ----------------\n\nlong long compute_vertical_delta(\n    const CellChange* chgs, int m,\n    const vector<int>& totalFullCnt,\n    vector<int>& pidSeen, vector<int>& pidDelta, int& pidStamp, vector<int>& touchedPid,\n    vector<int>& sidSeen, vector<int>& sidInc, vector<int>& sidDec, int& sidStamp, vector<int>& touchedSid\n) {\n    ++pidStamp;\n    if (pidStamp == INT_MAX) {\n        fill(pidSeen.begin(), pidSeen.end(), 0);\n        pidStamp = 1;\n    }\n    touchedPid.clear();\n\n    for (int i = 0; i < m; ++i) {\n        int cell = chgs[i].cell;\n        unsigned char oldc = chgs[i].oldc;\n        unsigned char newc = chgs[i].newc;\n        if (oldc == newc) continue;\n\n        for (const auto& e : vCellEdges[cell]) {\n            int vpid = e.pid;\n            if (pidSeen[vpid] != pidStamp) {\n                pidSeen[vpid] = pidStamp;\n                pidDelta[vpid] = 0;\n                touchedPid.push_back(vpid);\n            }\n            if (e.req == oldc) --pidDelta[vpid];\n            if (e.req == newc) ++pidDelta[vpid];\n        }\n    }\n\n    ++sidStamp;\n    if (sidStamp == INT_MAX) {\n        fill(sidSeen.begin(), sidSeen.end(), 0);\n        sidStamp = 1;\n    }\n    touchedSid.clear();\n\n    for (int vpid : touchedPid) {\n        int d = pidDelta[vpid];\n        if (d == 0) continue;\n        int sid = vPlSid[vpid];\n        if (sidSeen[sid] != sidStamp) {\n            sidSeen[sid] = sidStamp;\n            sidInc[sid] = 0;\n            sidDec[sid] = 0;\n            touchedSid.push_back(sid);\n        }\n\n        int oldm = vPlMatch[vpid];\n        int newm = oldm + d;\n        int len = vPlLen[vpid];\n\n        if (oldm == len && newm < len) ++sidDec[sid];\n        else if (oldm < len && newm == len) ++sidInc[sid];\n    }\n\n    long long delta = 0;\n    for (int sid : touchedSid) {\n        int oldCnt = totalFullCnt[sid];\n        int newCnt = oldCnt - sidDec[sid] + sidInc[sid];\n        if (oldCnt == 0 && newCnt > 0) delta += wt[sid];\n        else if (oldCnt > 0 && newCnt == 0) delta -= wt[sid];\n    }\n    return delta;\n}\n\nvoid apply_vertical_changes(\n    Matrix& mat,\n    const CellChange* chgs, int m,\n    vector<int>& totalFullCnt, long long& curScore,\n    vector<int>& pidSeen, vector<int>& pidDelta, int& pidStamp, vector<int>& touchedPid,\n    vector<int>& sidSeen, vector<int>& sidInc, vector<int>& sidDec, int& sidStamp, vector<int>& touchedSid\n) {\n    long long delta = compute_vertical_delta(\n        chgs, m, totalFullCnt,\n        pidSeen, pidDelta, pidStamp, touchedPid,\n        sidSeen, sidInc, sidDec, sidStamp, touchedSid\n    );\n\n    for (int vpid : touchedPid) {\n        int d = pidDelta[vpid];\n        if (d == 0) continue;\n        int oldm = vPlMatch[vpid];\n        int newm = oldm + d;\n        int sid = vPlSid[vpid];\n        int len = vPlLen[vpid];\n\n        if (oldm == len && newm < len) --totalFullCnt[sid];\n        else if (oldm < len && newm == len) ++totalFullCnt[sid];\n\n        vPlMatch[vpid] = (unsigned char)newm;\n    }\n\n    for (int i = 0; i < m; ++i) {\n        mat[chgs[i].cell] = chgs[i].newc;\n    }\n\n    curScore += delta;\n}\n\nStartResult exact_row_optimize(Matrix mat, long long endMs) {\n    vector<int> totalFullCnt;\n    long long curScore = init_state(mat, totalFullCnt);\n    init_vertical_state(mat);\n\n    const int U = (int)pats.size();\n    const int V = (int)vPlSid.size();\n\n    vector<int> pidSeen(V, 0), pidDelta(V, 0), touchedPid;\n    vector<int> sidSeen(U, 0), sidInc(U, 0), sidDec(U, 0), touchedSid;\n    touchedPid.reserve(160000);\n    touchedSid.reserve(U);\n\n    int pidStamp = 1, sidStamp = 1;\n\n    array<int, N> rowOrder{};\n    iota(rowOrder.begin(), rowOrder.end(), 0);\n\n    array<CellChange, N> shiftChg{};\n    array<CellChange, 2 * N> swapChg{};\n    array<CellChange, N * N> insChg{};\n\n    struct InsCand {\n        long long approx;\n        int i, j;\n    };\n    auto push_top_ins = [&](vector<InsCand>& top, long long approx, int i, int j, int cap = 8) {\n        top.push_back({approx, i, j});\n        int pos = (int)top.size() - 1;\n        while (pos > 0 && top[pos].approx > top[pos - 1].approx) {\n            swap(top[pos], top[pos - 1]);\n            --pos;\n        }\n        if ((int)top.size() > cap) top.pop_back();\n    };\n\n    auto approx_order_score = [&](const array<int, N>& ord) -> long long {\n        long long sc = 0;\n        for (int p = 0; p < N; ++p) {\n            int a = ord[p];\n            int b = ord[(p + 1) % N];\n            int c = ord[(p + 2) % N];\n            int ba = a * N, bb = b * N, bc = c * N;\n            for (int col = 0; col < N; ++col) {\n                unsigned char x = mat[ba + col];\n                unsigned char y = mat[bb + col];\n                unsigned char z = mat[bc + col];\n                sc += pairW[x][y];\n                sc += 2LL * triW[x][y][z];\n            }\n        }\n        return sc;\n    };\n\n    for (int outer = 0; outer < 2; ++outer) {\n        if (elapsed_ms() > endMs) break;\n        bool improved = false;\n\n        shuffle(rowOrder.begin(), rowOrder.end(), rng);\n\n        // row cyclic shifts\n        for (int rr = 0; rr < N; ++rr) {\n            if (elapsed_ms() > endMs) break;\n            int r = rowOrder[rr];\n            int base = r * N;\n\n            unsigned char oldRow[N];\n            for (int c = 0; c < N; ++c) oldRow[c] = mat[base + c];\n\n            long long bestDelta = 0;\n            int bestSh = 0;\n\n            for (int sh = 1; sh < N; ++sh) {\n                for (int c = 0; c < N; ++c) {\n                    shiftChg[c] = {base + c, oldRow[c], oldRow[(c + sh) % N]};\n                }\n\n                long long delta = compute_vertical_delta(\n                    shiftChg.data(), N, totalFullCnt,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestSh = sh;\n                }\n            }\n\n            if (bestSh != 0) {\n                for (int c = 0; c < N; ++c) {\n                    shiftChg[c] = {base + c, oldRow[c], oldRow[(c + bestSh) % N]};\n                }\n                apply_vertical_changes(\n                    mat, shiftChg.data(), N, totalFullCnt, curScore,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                improved = true;\n            }\n        }\n\n        if (elapsed_ms() > endMs) break;\n\n        // row swaps\n        for (int rep = 0; rep < 2; ++rep) {\n            if (elapsed_ms() > endMs) break;\n\n            long long bestDelta = 0;\n            int bi = -1, bj = -1;\n\n            for (int i = 0; i < N; ++i) {\n                if (elapsed_ms() > endMs) break;\n                int baseI = i * N;\n                for (int j = i + 1; j < N; ++j) {\n                    int baseJ = j * N;\n                    for (int c = 0; c < N; ++c) {\n                        swapChg[2 * c] = {baseI + c, mat[baseI + c], mat[baseJ + c]};\n                        swapChg[2 * c + 1] = {baseJ + c, mat[baseJ + c], mat[baseI + c]};\n                    }\n\n                    long long delta = compute_vertical_delta(\n                        swapChg.data(), 2 * N, totalFullCnt,\n                        pidSeen, pidDelta, pidStamp, touchedPid,\n                        sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                    );\n                    if (delta > bestDelta) {\n                        bestDelta = delta;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n\n            if (bi == -1) break;\n\n            int baseI = bi * N;\n            int baseJ = bj * N;\n            for (int c = 0; c < N; ++c) {\n                swapChg[2 * c] = {baseI + c, mat[baseI + c], mat[baseJ + c]};\n                swapChg[2 * c + 1] = {baseJ + c, mat[baseJ + c], mat[baseI + c]};\n            }\n\n            apply_vertical_changes(\n                mat, swapChg.data(), 2 * N, totalFullCnt, curScore,\n                pidSeen, pidDelta, pidStamp, touchedPid,\n                sidSeen, sidInc, sidDec, sidStamp, touchedSid\n            );\n            improved = true;\n        }\n\n        if (elapsed_ms() > endMs) break;\n\n        // row insertions, shortlisted by n-gram score\n        for (int rep = 0; rep < 2; ++rep) {\n            if (elapsed_ms() > endMs) break;\n\n            array<int, N> ord{};\n            iota(ord.begin(), ord.end(), 0);\n            long long curApprox = approx_order_score(ord);\n\n            vector<InsCand> topIns;\n            topIns.reserve(8);\n\n            for (int i = 0; i < N; ++i) {\n                for (int j = 0; j < N; ++j) {\n                    if (i == j) continue;\n                    array<int, N> tmp = ord;\n                    int v = tmp[i];\n                    if (i < j) {\n                        for (int t = i; t < j; ++t) tmp[t] = tmp[t + 1];\n                        tmp[j] = v;\n                    } else {\n                        for (int t = i; t > j; --t) tmp[t] = tmp[t - 1];\n                        tmp[j] = v;\n                    }\n                    long long sc = approx_order_score(tmp);\n                    push_top_ins(topIns, sc - curApprox, i, j, 8);\n                }\n            }\n\n            unsigned char oldRows[N][N];\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) oldRows[r][c] = mat[r * N + c];\n            }\n\n            long long bestDelta = 0;\n            int bestI = -1, bestJ = -1;\n\n            for (auto cand : topIns) {\n                int i = cand.i, j = cand.j;\n                int m = 0;\n\n                if (i < j) {\n                    for (int r = i; r < j; ++r) {\n                        for (int c = 0; c < N; ++c) {\n                            insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r + 1][c]};\n                        }\n                    }\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {j * N + c, oldRows[j][c], oldRows[i][c]};\n                    }\n                } else {\n                    for (int r = i; r > j; --r) {\n                        for (int c = 0; c < N; ++c) {\n                            insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r - 1][c]};\n                        }\n                    }\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {j * N + c, oldRows[j][c], oldRows[i][c]};\n                    }\n                }\n\n                long long delta = compute_vertical_delta(\n                    insChg.data(), m, totalFullCnt,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n\n            if (bestI == -1) break;\n\n            int m = 0;\n            if (bestI < bestJ) {\n                for (int r = bestI; r < bestJ; ++r) {\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r + 1][c]};\n                    }\n                }\n                for (int c = 0; c < N; ++c) {\n                    insChg[m++] = {bestJ * N + c, oldRows[bestJ][c], oldRows[bestI][c]};\n                }\n            } else {\n                for (int r = bestI; r > bestJ; --r) {\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r - 1][c]};\n                    }\n                }\n                for (int c = 0; c < N; ++c) {\n                    insChg[m++] = {bestJ * N + c, oldRows[bestJ][c], oldRows[bestI][c]};\n                }\n            }\n\n            apply_vertical_changes(\n                mat, insChg.data(), m, totalFullCnt, curScore,\n                pidSeen, pidDelta, pidStamp, touchedPid,\n                sidSeen, sidInc, sidDec, sidStamp, touchedSid\n            );\n            improved = true;\n        }\n\n        if (!improved) break;\n    }\n\n    return {curScore, mat};\n}\n\n// ---------------- main ----------------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gStart = chrono::steady_clock::now();\n\n    int Nin, M;\n    cin >> Nin >> M;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M * 2);\n\n    vector<int> charFreq(8, 0);\n\n    for (int i = 0; i < M; ++i) {\n        string s;\n        cin >> s;\n        auto it = mp.find(s);\n        if (it == mp.end()) {\n            int id = (int)pats.size();\n            mp.emplace(s, id);\n            pats.push_back(s);\n            wt.push_back(1);\n        } else {\n            wt[it->second]++;\n        }\n        for (char c : s) ++charFreq[c - 'A'];\n    }\n\n    int U = (int)pats.size();\n    pch.resize(U);\n    for (int i = 0; i < U; ++i) {\n        pch[i].resize(pats[i].size());\n        for (int j = 0; j < (int)pats[i].size(); ++j) {\n            pch[i][j] = (unsigned char)(pats[i][j] - 'A');\n        }\n    }\n\n    memset(pairW, 0, sizeof(pairW));\n    memset(triW, 0, sizeof(triW));\n    for (int sid = 0; sid < U; ++sid) {\n        const auto& s = pch[sid];\n        int k = (int)s.size();\n        for (int i = 0; i + 1 < k; ++i) pairW[s[i]][s[i + 1]] += wt[sid];\n        for (int i = 0; i + 2 < k; ++i) triW[s[i]][s[i + 1]][s[i + 2]] += wt[sid];\n    }\n\n    vector<long long> imp(U);\n    for (int i = 0; i < U; ++i) {\n        int L = (int)pats[i].size();\n        imp[i] = 1LL * wt[i] * L * L;\n    }\n    impOrder.resize(U);\n    iota(impOrder.begin(), impOrder.end(), 0);\n    sort(impOrder.begin(), impOrder.end(), [&](int a, int b) {\n        if (imp[a] != imp[b]) return imp[a] > imp[b];\n        return pats[a].size() > pats[b].size();\n    });\n\n    // Stage 1: row assembly\n    vector<string> rows = build_initial_rows(charFreq);\n\n    // Stage 2: exact graph\n    build_exact_graph();\n\n    // Stage 3: build diverse starts\n    vector<Matrix> starts;\n\n    {\n        vector<Matrix> ng = build_ngram_starts(rows);\n        for (auto& m : ng) starts.push_back(m);\n    }\n\n    starts.push_back(make_matrix_from_rows(rows, false, false));\n    starts.push_back(make_matrix_from_rows(rows, false, true));\n    starts.push_back(make_matrix_from_rows(rows, true, false));\n    starts.push_back(make_matrix_from_rows(rows, true, true));\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n    starts.push_back(make_constant_matrix(bestChar));\n    starts.push_back(make_random_freq_matrix(charFreq));\n\n    // soft refinement on starts\n    vector<StartResult> refined;\n    refined.reserve(starts.size());\n\n    long long softDeadline = 1650;\n    for (int i = 0; i < (int)starts.size(); ++i) {\n        if (elapsed_ms() > softDeadline) break;\n\n        vector<int> kinds, inertias;\n        if (elapsed_ms() < 1200) {\n            kinds = {0, 1, 2, 3};\n            inertias = {120, 60, 36, 20};\n        } else {\n            kinds = {0, 1, 2};\n            inertias = {100, 50, 28};\n        }\n\n        StartResult res = soft_refine(starts[i], kinds, inertias, softDeadline);\n        refined.push_back(res);\n    }\n\n    if (refined.empty()) {\n        vector<int> tmp;\n        refined.push_back({init_state(starts[0], tmp), starts[0]});\n    }\n\n    sort(refined.begin(), refined.end(), [&](const StartResult& a, const StartResult& b) {\n        return a.score > b.score;\n    });\n\n    StartResult globalBest = refined[0];\n\n    // exact hill-climb on top starts\n    long long hcEnd = 2520;\n    for (int i = 0; i < min<int>(2, refined.size()); ++i) {\n        if (elapsed_ms() > hcEnd) break;\n        int maxPass = (i == 0 ? 2 : 1);\n        StartResult res = exact_hillclimb(refined[i].mat, maxPass, hcEnd);\n        if (res.score > globalBest.score) globalBest = res;\n    }\n\n    // zero-cost structural polish: row shifts/swaps/insertions\n    if (elapsed_ms() < 2840) {\n        StartResult z = exact_row_optimize(globalBest.mat, 2840);\n        if (z.score >= globalBest.score) globalBest = z;\n    }\n\n    // transpose -> same polish -> transpose back\n    if (elapsed_ms() < 2925) {\n        Matrix t = transpose_matrix(globalBest.mat);\n        StartResult zt = exact_row_optimize(t, 2925);\n        zt.mat = transpose_matrix(zt.mat);\n        if (zt.score >= globalBest.score) globalBest = zt;\n    }\n\n    // final exact polish\n    if (elapsed_ms() < 2965) {\n        StartResult res = exact_hillclimb(globalBest.mat, 1, 2965);\n        if (res.score > globalBest.score) globalBest = res;\n    }\n\n    // light kick + exact polish\n    if (elapsed_ms() < 2985) {\n        StartResult kicked = soft_refine(globalBest.mat, {4}, {14}, 2990);\n        if (elapsed_ms() < 2995) {\n            StartResult res = exact_hillclimb(kicked.mat, 1, 2995);\n            if (res.score > globalBest.score) globalBest = res;\n            else if (kicked.score > globalBest.score) globalBest = kicked;\n        } else {\n            if (kicked.score > globalBest.score) globalBest = kicked;\n        }\n    }\n\n    // output\n    for (int r = 0; r < N; ++r) {\n        string out(N, 'A');\n        for (int c = 0; c < N; ++c) out[c] = char('A' + globalBest.mat[r * N + c]);\n        cout << out << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\n\nstatic constexpr int INF_INT = 1e9;\nstatic constexpr ll INF_LL = (ll)4e18;\n\nstruct Task {\n    // type: 0=fixed cell, 1=horizontal segment, 2=vertical segment\n    int type;\n    int seg;\n    int cell;\n};\n\nstruct CandidateResult {\n    bool valid = false;\n    ll cost = INF_LL;\n    string path;\n};\n\nint N, si, sj;\nvector<string> gridc;\nvector<vector<int>> idg;\n\nint Rcnt, sId;\nvector<int> rr, cc, cellW;\nvector<vector<int>> nbrs;\n\nint Hcnt, Vcnt;\nvector<int> hid, vid;\nvector<vector<int>> cellsH, cellsV;\nvector<vector<pair<int,int>>> adjHFull, adjHRes; // (v, cell)\n\nint sH, sV;\nvector<char> activeH, activeV;\nvector<int> bestCellH, bestCellV;\nvector<int> distStart;\n\nvector<char> dijReady;\nvector<vector<int>> distCache, parentCache;\n\nchrono::steady_clock::time_point globalStart;\n\nll elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - globalStart\n    ).count();\n}\n\nchar dirChar(int a, int b) {\n    if (rr[b] == rr[a] - 1 && cc[b] == cc[a]) return 'U';\n    if (rr[b] == rr[a] + 1 && cc[b] == cc[a]) return 'D';\n    if (rr[b] == rr[a] && cc[b] == cc[a] - 1) return 'L';\n    if (rr[b] == rr[a] && cc[b] == cc[a] + 1) return 'R';\n    return '?';\n}\n\nvoid runDijkstra(int src, vector<int>& dist, vector<int>& parent) {\n    dist.assign(Rcnt, INF_INT);\n    parent.assign(Rcnt, -1);\n    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [d, u] = pq.top();\n        pq.pop();\n        if (d != dist[u]) continue;\n        for (int v : nbrs[u]) {\n            int nd = d + cellW[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                parent[v] = u;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\nvoid ensureDijkstra(int src) {\n    if (dijReady[src]) return;\n    dijReady[src] = true;\n    runDijkstra(src, distCache[src], parentCache[src]);\n}\n\npair<bool,ll> validateAndCost(const string& path) {\n    vector<char> covH(Hcnt, false), covV(Vcnt, false);\n    int cur = sId;\n    covH[hid[cur]] = true;\n    covV[vid[cur]] = true;\n    ll cost = 0;\n\n    for (char ch : path) {\n        int ni = rr[cur], nj = cc[cur];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return {false, 0};\n\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return {false, 0};\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return {false, 0};\n\n        cost += cellW[nxt];\n        cur = nxt;\n        covH[hid[cur]] = true;\n        covV[vid[cur]] = true;\n    }\n\n    if (cur != sId) return {false, 0};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        if (!covH[hid[cid]] && !covV[vid[cid]]) return {false, 0};\n    }\n    return {true, cost};\n}\n\nvoid hopcroftKarp(\n    const vector<char>& selH,\n    const vector<char>& selV,\n    const vector<vector<pair<int,int>>>& adj,\n    vector<int>& matchH,\n    vector<int>& matchV\n) {\n    matchH.assign(Hcnt, -1);\n    matchV.assign(Vcnt, -1);\n    vector<int> level(Hcnt, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(level.begin(), level.end(), -1);\n        bool found = false;\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) {\n                level[h] = 0;\n                q.push(h);\n            }\n        }\n        while (!q.empty()) {\n            int h = q.front(); q.pop();\n            for (auto [v, cid] : adj[h]) {\n                (void)cid;\n                if (!selV[v]) continue;\n                int h2 = matchV[v];\n                if (h2 == -1) {\n                    found = true;\n                } else if (level[h2] == -1) {\n                    level[h2] = level[h] + 1;\n                    q.push(h2);\n                }\n            }\n        }\n        return found;\n    };\n\n    function<bool(int)> dfs = [&](int h) -> bool {\n        for (auto [v, cid] : adj[h]) {\n            (void)cid;\n            if (!selV[v]) continue;\n            int h2 = matchV[v];\n            if (h2 == -1 || (level[h2] == level[h] + 1 && dfs(h2))) {\n                matchH[h] = v;\n                matchV[v] = h;\n                return true;\n            }\n        }\n        level[h] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) dfs(h);\n        }\n    }\n}\n\npair<vector<char>, vector<char>> buildCanonicalMVC() {\n    vector<int> matchH, matchV;\n    hopcroftKarp(activeH, activeV, adjHRes, matchH, matchV);\n\n    vector<char> visH(Hcnt, false), visV(Vcnt, false);\n    queue<int> q;\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h] && matchH[h] == -1) {\n            visH[h] = true;\n            q.push(h);\n        }\n    }\n\n    while (!q.empty()) {\n        int h = q.front(); q.pop();\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (matchH[h] == v) continue;\n            if (!visV[v]) {\n                visV[v] = true;\n                int h2 = matchV[v];\n                if (h2 != -1 && !visH[h2]) {\n                    visH[h2] = true;\n                    q.push(h2);\n                }\n            }\n        }\n    }\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !visH[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && visV[v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\npair<vector<char>, vector<char>> buildWeightedVC(\n    const vector<ll>& wH,\n    const vector<ll>& wV\n) {\n    int S = Hcnt + Vcnt;\n    int T = S + 1;\n    mf_graph<ll> mf(T + 1);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) mf.add_edge(S, h, wH[h]);\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) mf.add_edge(Hcnt + v, T, wV[v]);\n    }\n    for (int h = 0; h < Hcnt; h++) {\n        if (!activeH[h]) continue;\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (!activeV[v]) continue;\n            mf.add_edge(h, Hcnt + v, INF_LL / 8);\n        }\n    }\n\n    mf.flow(S, T);\n    auto reach = mf.min_cut(S);\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !reach[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && reach[Hcnt + v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\nvector<Task> compressTasksByCell(vector<Task> tasks) {\n    vector<vector<Task>> buckets(Rcnt);\n    for (auto &t : tasks) buckets[t.cell].push_back(t);\n\n    vector<Task> out;\n    out.reserve(tasks.size());\n    for (int c = 0; c < Rcnt; c++) {\n        if (buckets[c].empty()) continue;\n        if (buckets[c].size() >= 2) {\n            out.push_back({0, -1, c});\n        } else {\n            out.push_back(buckets[c][0]);\n        }\n    }\n    sort(out.begin(), out.end(), [&](const Task& a, const Task& b) {\n        if (a.cell != b.cell) return a.cell < b.cell;\n        if (a.type != b.type) return a.type < b.type;\n        return a.seg < b.seg;\n    });\n    return out;\n}\n\nvector<Task> buildTasksPaired(const vector<char>& selH, const vector<char>& selV) {\n    vector<int> matchH, matchV;\n    hopcroftKarp(selH, selV, adjHFull, matchH, matchV);\n\n    vector<Task> tasks;\n    for (int h = 0; h < Hcnt; h++) {\n        if (!selH[h]) continue;\n        if (matchH[h] != -1) {\n            int v = matchH[h];\n            int cid = -1;\n            for (auto [vv, ccid] : adjHFull[h]) {\n                if (vv == v) {\n                    cid = ccid;\n                    break;\n                }\n            }\n            if (cid != -1) tasks.push_back({0, -1, cid});\n        }\n    }\n    for (int h = 0; h < Hcnt; h++) {\n        if (selH[h] && matchH[h] == -1) tasks.push_back({1, h, bestCellH[h]});\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (selV[v] && matchV[v] == -1) tasks.push_back({2, v, bestCellV[v]});\n    }\n    return compressTasksByCell(tasks);\n}\n\nvector<Task> buildTasksNoPair(const vector<char>& selH, const vector<char>& selV) {\n    vector<Task> tasks;\n    for (int h = 0; h < Hcnt; h++) if (selH[h]) tasks.push_back({1, h, bestCellH[h]});\n    for (int v = 0; v < Vcnt; v++) if (selV[v]) tasks.push_back({2, v, bestCellV[v]});\n    return compressTasksByCell(tasks);\n}\n\nvector<Task> buildTasksGreedyPair(const vector<char>& selH, const vector<char>& selV, ll penalty) {\n    struct E {\n        ll gain;\n        int h, v, cid;\n    };\n    vector<E> es;\n    for (int h = 0; h < Hcnt; h++) {\n        if (!selH[h]) continue;\n        ll baseH = distStart[bestCellH[h]];\n        for (auto [v, cid] : adjHFull[h]) {\n            if (!selV[v]) continue;\n            ll gain = baseH + (ll)distStart[bestCellV[v]] - (ll)distStart[cid] - penalty;\n            if (gain > 0) es.push_back({gain, h, v, cid});\n        }\n    }\n    sort(es.begin(), es.end(), [&](const E& a, const E& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (distStart[a.cid] != distStart[b.cid]) return distStart[a.cid] < distStart[b.cid];\n        return a.cid < b.cid;\n    });\n\n    vector<char> usedH(Hcnt, false), usedV(Vcnt, false);\n    vector<Task> tasks;\n    for (auto &e : es) {\n        if (usedH[e.h] || usedV[e.v]) continue;\n        usedH[e.h] = true;\n        usedV[e.v] = true;\n        tasks.push_back({0, -1, e.cid});\n    }\n    for (int h = 0; h < Hcnt; h++) if (selH[h] && !usedH[h]) tasks.push_back({1, h, bestCellH[h]});\n    for (int v = 0; v < Vcnt; v++) if (selV[v] && !usedV[v]) tasks.push_back({2, v, bestCellV[v]});\n\n    return compressTasksByCell(tasks);\n}\n\nstring makeTaskSig(const vector<Task>& tasks) {\n    string s;\n    s.reserve(tasks.size() * 12);\n    for (auto &t : tasks) {\n        s += char('0' + t.type);\n        s += ':';\n        s += to_string(t.seg);\n        s += ':';\n        s += to_string(t.cell);\n        s += ';';\n    }\n    return s;\n}\n\nbool buildData(\n    const vector<Task>& tasks,\n    vector<int>& sourceCells,\n    vector<vector<ll>>& d0\n) {\n    if (elapsed_ms() > 2820) return false;\n    int M = (int)tasks.size() + 1;\n    sourceCells.assign(M, -1);\n    sourceCells[0] = sId;\n    for (int i = 0; i < (int)tasks.size(); i++) sourceCells[i + 1] = tasks[i].cell;\n\n    for (int i = 0; i < M; i++) ensureDijkstra(sourceCells[i]);\n\n    d0.assign(M, vector<ll>(M, 0));\n    for (int i = 0; i < M; i++) {\n        int ci = sourceCells[i];\n        for (int j = 0; j < M; j++) {\n            if (i == j) d0[i][j] = 0;\n            else d0[i][j] = (ll)distCache[ci][sourceCells[j]] + cellW[ci];\n        }\n    }\n    return true;\n}\n\nll routeCostMat(const vector<int>& route, const vector<vector<ll>>& d0) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) s += d0[route[i]][route[i + 1]];\n    return s;\n}\n\nll routeActualCost(const vector<int>& route, const vector<int>& sourceCells) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distCache[sourceCells[route[i]]][sourceCells[route[i + 1]]];\n    }\n    return s;\n}\n\nvector<int> routeNearestNeighbor(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    vector<int> route;\n    route.reserve(M + 2);\n    route.push_back(0);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    int cur = 0;\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        ll bestD = INF_LL;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeNearestSeed(const vector<vector<ll>>& d0, int first) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n    if (first < 1 || first > M) return routeNearestNeighbor(d0);\n\n    vector<int> route;\n    route.reserve(M + 2);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    used[first] = true;\n    route.push_back(0);\n    route.push_back(first);\n    int cur = first;\n\n    for (int step = 1; step < M; step++) {\n        int best = -1;\n        ll bestD = INF_LL;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeCheapestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    used[0] = true;\n\n    int first = 1;\n    ll bestFirst = INF_LL;\n    for (int p = 1; p <= M; p++) {\n        ll val = d0[0][p] + d0[p][0];\n        if (val < bestFirst) {\n            bestFirst = val;\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        ll bestInc = INF_LL;\n        int bestP = -1, bestPos = -1;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n                int a = route[pos], b = route[pos + 1];\n                ll inc = d0[a][p] + d0[p][b] - d0[a][b];\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestP = p;\n                    bestPos = pos;\n                }\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, bestP);\n        used[bestP] = true;\n    }\n    return route;\n}\n\nvector<int> routeFarthestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    int first = 1;\n    ll far = -1;\n    for (int p = 1; p <= M; p++) {\n        if (d0[0][p] > far) {\n            far = d0[0][p];\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        int pick = -1;\n        ll bestFar = -1;\n        for (int p = 1; p <= M; p++) if (!used[p]) {\n            ll mn = INF_LL;\n            for (int x : route) mn = min(mn, d0[x][p]);\n            if (mn > bestFar) {\n                bestFar = mn;\n                pick = p;\n            }\n        }\n\n        ll bestInc = INF_LL;\n        int bestPos = -1;\n        for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n            int a = route[pos], b = route[pos + 1];\n            ll inc = d0[a][pick] + d0[pick][b] - d0[a][b];\n            if (inc < bestInc) {\n                bestInc = inc;\n                bestPos = pos;\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, pick);\n        used[pick] = true;\n    }\n\n    return route;\n}\n\nvoid improve2opt(vector<int>& route, const vector<vector<ll>>& d0) {\n    int M = (int)route.size() - 2;\n    int maxPass = (M <= 35 ? 4 : M <= 70 ? 2 : 1);\n    int L = (int)route.size();\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool improved = false;\n        for (int i = 1; i + 2 < L; i++) {\n            for (int j = i + 1; j + 1 < L; j++) {\n                ll oldv = d0[route[i - 1]][route[i]] + d0[route[j]][route[j + 1]];\n                ll newv = d0[route[i - 1]][route[j]] + d0[route[i]][route[j + 1]];\n                if (newv < oldv) {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n        if (!improved || elapsed_ms() > 2750) break;\n    }\n}\n\nbool improveRelocateOnce(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    for (int i = 1; i + 1 < L; i++) {\n        int a = route[i - 1], x = route[i], b = route[i + 1];\n        for (int j = 0; j + 1 < L; j++) {\n            if (j == i || j == i - 1) continue;\n            int c = route[j], d = route[j + 1];\n            ll oldv = d0[a][x] + d0[x][b] + d0[c][d];\n            ll newv = d0[a][b] + d0[c][x] + d0[x][d];\n            if (newv < oldv) {\n                int val = route[i];\n                route.erase(route.begin() + i);\n                if (j < i) route.insert(route.begin() + (j + 1), val);\n                else route.insert(route.begin() + j, val);\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nbool improveSwapOnce(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    for (int i = 1; i + 1 < L; i++) {\n        for (int j = i + 1; j + 1 < L; j++) {\n            ll oldv, newv;\n            int x = route[i], y = route[j];\n            if (j == i + 1) {\n                int a = route[i - 1], d = route[j + 1];\n                oldv = d0[a][x] + d0[x][y] + d0[y][d];\n                newv = d0[a][y] + d0[y][x] + d0[x][d];\n            } else {\n                int a = route[i - 1], b = route[i + 1];\n                int c = route[j - 1], d = route[j + 1];\n                oldv = d0[a][x] + d0[x][b] + d0[c][y] + d0[y][d];\n                newv = d0[a][y] + d0[y][b] + d0[c][x] + d0[x][d];\n            }\n            if (newv < oldv) {\n                swap(route[i], route[j]);\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nvoid improveRoute(vector<int>& route, const vector<vector<ll>>& d0) {\n    int M = (int)route.size() - 2;\n    improve2opt(route, d0);\n\n    if (M <= 40 && elapsed_ms() < 2650) {\n        for (int iter = 0; iter < 6; iter++) {\n            bool imp = false;\n            if (improveRelocateOnce(route, d0)) {\n                imp = true;\n                improve2opt(route, d0);\n            }\n            if (improveSwapOnce(route, d0)) {\n                imp = true;\n                improve2opt(route, d0);\n            }\n            if (!imp || elapsed_ms() > 2750) break;\n        }\n    }\n}\n\nvector<int> exactRoute(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n    if (M == 1) return {0, 1, 0};\n\n    int S = 1 << M;\n    vector<vector<ll>> dp(S, vector<ll>(M, INF_LL));\n    vector<vector<short>> pre(S, vector<short>(M, -1));\n\n    for (int i = 0; i < M; i++) dp[1 << i][i] = d0[0][i + 1];\n\n    for (int mask = 1; mask < S; mask++) {\n        for (int i = 0; i < M; i++) {\n            if (!(mask & (1 << i))) continue;\n            ll cur = dp[mask][i];\n            if (cur >= INF_LL / 4) continue;\n            int rem = ((S - 1) ^ mask);\n            while (rem) {\n                int b = rem & -rem;\n                int j = __builtin_ctz(b);\n                int nmask = mask | b;\n                ll nd = cur + d0[i + 1][j + 1];\n                if (nd < dp[nmask][j]) {\n                    dp[nmask][j] = nd;\n                    pre[nmask][j] = (short)i;\n                }\n                rem ^= b;\n            }\n        }\n    }\n\n    int all = S - 1;\n    ll best = INF_LL;\n    int last = -1;\n    for (int i = 0; i < M; i++) {\n        ll val = dp[all][i] + d0[i + 1][0];\n        if (val < best) {\n            best = val;\n            last = i;\n        }\n    }\n\n    vector<int> ord;\n    int mask = all;\n    while (last != -1) {\n        ord.push_back(last + 1);\n        int pl = pre[mask][last];\n        mask ^= (1 << last);\n        last = pl;\n    }\n    reverse(ord.begin(), ord.end());\n\n    vector<int> route;\n    route.push_back(0);\n    for (int x : ord) route.push_back(x);\n    route.push_back(0);\n    return route;\n}\n\nvector<int> buildBestOrder(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    if (M <= 16 && elapsed_ms() < 650) return exactRoute(d0);\n    if (M <= 15 && elapsed_ms() < 1200) return exactRoute(d0);\n    if (M <= 14 && elapsed_ms() < 1850) return exactRoute(d0);\n    if (M <= 13 && elapsed_ms() < 2350) return exactRoute(d0);\n\n    vector<vector<int>> cands;\n    cands.push_back(routeCheapestInsertion(d0));\n    cands.push_back(routeNearestNeighbor(d0));\n    if (M <= 60) cands.push_back(routeFarthestInsertion(d0));\n\n    if (M >= 2 && M <= 70) {\n        vector<pair<ll,int>> ord;\n        ord.reserve(M);\n        for (int p = 1; p <= M; p++) ord.push_back({d0[0][p], p});\n        sort(ord.begin(), ord.end(), greater<pair<ll,int>>());\n        cands.push_back(routeNearestSeed(d0, ord[0].second));\n        if (M >= 3) cands.push_back(routeNearestSeed(d0, ord[1].second));\n        if (M >= 4) cands.push_back(routeNearestSeed(d0, ord[2].second));\n    }\n\n    ll best = INF_LL;\n    vector<int> bestRoute;\n\n    for (auto route : cands) {\n        improveRoute(route, d0);\n        ll c = routeCostMat(route, d0);\n        if (c < best) {\n            best = c;\n            bestRoute = move(route);\n        }\n        if (elapsed_ms() > 2780) break;\n    }\n    return bestRoute;\n}\n\nbool refineTaskCells(vector<Task>& tasks, const vector<int>& route, const vector<int>& sourceCells) {\n    int M = (int)tasks.size();\n    vector<int> pos(M + 1, -1);\n    for (int i = 0; i < (int)route.size(); i++) pos[route[i]] = i;\n\n    bool changed = false;\n    for (int ti = 0; ti < M; ti++) {\n        if (tasks[ti].type == 0) continue;\n        int idx = ti + 1;\n        int p = pos[idx];\n        if (p <= 0 || p + 1 >= (int)route.size()) continue;\n\n        int prevCell = sourceCells[route[p - 1]];\n        int nextCell = sourceCells[route[p + 1]];\n        const vector<int>& candCells =\n            (tasks[ti].type == 1 ? cellsH[tasks[ti].seg] : cellsV[tasks[ti].seg]);\n\n        ll bestVal = INF_LL;\n        int bestCid = tasks[ti].cell;\n        for (int cid : candCells) {\n            ll val = (ll)distCache[prevCell][cid]\n                   + (ll)distCache[nextCell][cid]\n                   + cellW[nextCell] - cellW[cid];\n            if (val < bestVal) {\n                bestVal = val;\n                bestCid = cid;\n            } else if (val == bestVal) {\n                if (distStart[cid] < distStart[bestCid]) bestCid = cid;\n            }\n        }\n        if (bestCid != tasks[ti].cell) {\n            tasks[ti].cell = bestCid;\n            changed = true;\n        }\n    }\n    return changed;\n}\n\nstring reconstructPath(const vector<int>& route, const vector<int>& sourceCells) {\n    string out;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        int src = sourceCells[route[i]];\n        int dst = sourceCells[route[i + 1]];\n        if (src == dst) continue;\n\n        vector<int> rev;\n        int cur = dst;\n        while (cur != src) {\n            int p = parentCache[src][cur];\n            if (p == -1) return \"\";\n            rev.push_back(cur);\n            cur = p;\n        }\n        reverse(rev.begin(), rev.end());\n\n        int prev = src;\n        for (int x : rev) {\n            char c = dirChar(prev, x);\n            if (c == '?') return \"\";\n            out.push_back(c);\n            prev = x;\n        }\n    }\n    return out;\n}\n\nstring pruneOneLoop(const string& path) {\n    if (path.empty()) return path;\n\n    int L = (int)path.size();\n    vector<int> pos(L + 1);\n    pos[0] = sId;\n    int cur = sId;\n    for (int i = 0; i < L; i++) {\n        int ni = rr[cur], nj = cc[cur];\n        char ch = path[i];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return path;\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return path;\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return path;\n        cur = nxt;\n        pos[i + 1] = cur;\n    }\n\n    vector<int> cntH(Hcnt, 0), cntV(Vcnt, 0);\n    for (int x : pos) {\n        cntH[hid[x]]++;\n        cntV[vid[x]]++;\n    }\n\n    vector<int> last(Rcnt, -1);\n    vector<int> tmpH(Hcnt, 0), tmpV(Vcnt, 0);\n    vector<int> touchedH, touchedV;\n\n    for (int r = 0; r <= L; r++) {\n        int cell = pos[r];\n        int l = last[cell];\n        if (l != -1 && r > l) {\n            touchedH.clear();\n            touchedV.clear();\n            for (int k = l + 1; k <= r; k++) {\n                int c = pos[k];\n                int h = hid[c], v = vid[c];\n                if (tmpH[h]++ == 0) touchedH.push_back(h);\n                if (tmpV[v]++ == 0) touchedV.push_back(v);\n            }\n\n            bool ok = true;\n            for (int h : touchedH) {\n                if (cntH[h] - tmpH[h] == 0) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) {\n                for (int v : touchedV) {\n                    if (cntV[v] - tmpV[v] == 0) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n\n            for (int h : touchedH) tmpH[h] = 0;\n            for (int v : touchedV) tmpV[v] = 0;\n\n            if (ok) {\n                string res;\n                res.reserve(path.size() - (r - l));\n                res.append(path.begin(), path.begin() + l);\n                res.append(path.begin() + r, path.end());\n                return res;\n            }\n        }\n        last[cell] = r;\n    }\n    return path;\n}\n\nstring pruneLoops(string path) {\n    for (int pass = 0; pass < 4; pass++) {\n        if (elapsed_ms() > 2890) break;\n        string np = pruneOneLoop(path);\n        if (np.size() == path.size()) break;\n        auto [ok, c] = validateAndCost(np);\n        (void)c;\n        if (!ok) break;\n        path = move(np);\n    }\n    return path;\n}\n\nvoid tryDeleteWaypointBlock(\n    vector<int>& route,\n    const vector<int>& sourceCells,\n    string& curPath,\n    ll& curCost,\n    int blockLen,\n    int maxPass\n) {\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool improved = false;\n        for (int i = 1; i + blockLen < (int)route.size(); i++) {\n            if (elapsed_ms() > 2830) return;\n            if (i + blockLen >= (int)route.size() - 1) break;\n\n            int a = sourceCells[route[i - 1]];\n            int c = sourceCells[route[i + blockLen]];\n\n            ll oldPart = 0;\n            for (int k = i - 1; k < i + blockLen; k++) {\n                int x = sourceCells[route[k]];\n                int y = sourceCells[route[k + 1]];\n                oldPart += (ll)distCache[x][y];\n            }\n            ll newPart = (ll)distCache[a][c];\n            if (newPart >= oldPart) continue;\n\n            vector<int> candRoute = route;\n            candRoute.erase(candRoute.begin() + i, candRoute.begin() + i + blockLen);\n\n            string candPath = reconstructPath(candRoute, sourceCells);\n            if (candPath.empty()) continue;\n\n            auto [ok, cost] = validateAndCost(candPath);\n            if (ok && cost < curCost) {\n                route.swap(candRoute);\n                curPath.swap(candPath);\n                curCost = cost;\n                improved = true;\n                break;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvoid deleteRedundantWaypoints(vector<int>& route, const vector<int>& sourceCells, string& curPath, ll& curCost) {\n    int M = (int)route.size() - 2;\n    if (M > 35) return;\n    if (elapsed_ms() > 2700) return;\n\n    tryDeleteWaypointBlock(route, sourceCells, curPath, curCost, 1, 2);\n\n    M = (int)route.size() - 2;\n    if (M <= 28 && elapsed_ms() <= 2790) {\n        tryDeleteWaypointBlock(route, sourceCells, curPath, curCost, 2, 1);\n    }\n}\n\nCandidateResult solveCandidate(vector<Task> tasks) {\n    CandidateResult res;\n    tasks = compressTasksByCell(tasks);\n\n    if ((int)tasks.size() > 90) return res;\n    if (elapsed_ms() > 2810) return res;\n\n    if (tasks.empty()) {\n        auto [ok, c] = validateAndCost(\"\");\n        if (ok) {\n            res.valid = true;\n            res.cost = c;\n            res.path = \"\";\n        }\n        return res;\n    }\n\n    vector<int> sourceCells;\n    vector<vector<ll>> d0;\n\n    if (!buildData(tasks, sourceCells, d0)) return res;\n    vector<int> route = buildBestOrder(d0);\n    ll bestRouteCost = routeActualCost(route, sourceCells);\n\n    if (elapsed_ms() < 2650) {\n        vector<Task> tasks2 = tasks;\n        if (refineTaskCells(tasks2, route, sourceCells)) {\n            tasks2 = compressTasksByCell(tasks2);\n            if ((int)tasks2.size() <= 90) {\n                vector<int> sourceCells2;\n                vector<vector<ll>> d02;\n                if (buildData(tasks2, sourceCells2, d02)) {\n                    auto route2 = buildBestOrder(d02);\n                    ll cost2 = routeActualCost(route2, sourceCells2);\n                    if (cost2 < bestRouteCost) {\n                        tasks = move(tasks2);\n                        sourceCells = move(sourceCells2);\n                        d0 = move(d02);\n                        route = move(route2);\n                        bestRouteCost = cost2;\n                    }\n                }\n            }\n        }\n    }\n\n    string path = reconstructPath(route, sourceCells);\n    auto [ok, c] = validateAndCost(path);\n    if (!ok) return res;\n\n    deleteRedundantWaypoints(route, sourceCells, path, c);\n\n    if ((int)route.size() - 2 <= 20 && elapsed_ms() < 2790) {\n        string p2 = pruneOneLoop(path);\n        if (p2.size() < path.size()) {\n            auto [ok2, c2] = validateAndCost(p2);\n            if (ok2 && c2 < c) {\n                path = move(p2);\n                c = c2;\n            }\n        }\n    }\n\n    res.valid = true;\n    res.cost = c;\n    res.path = move(path);\n    return res;\n}\n\nstring buildFallbackDFSRoute() {\n    vector<char> vis(Rcnt, false);\n    string out;\n\n    vector<int> it(Rcnt, 0);\n    vector<int> st;\n    st.push_back(sId);\n    vis[sId] = true;\n\n    while (!st.empty()) {\n        int u = st.back();\n        if (it[u] == (int)nbrs[u].size()) {\n            st.pop_back();\n            if (!st.empty()) {\n                int p = st.back();\n                out.push_back(dirChar(u, p));\n            }\n            continue;\n        }\n        int v = nbrs[u][it[u]++];\n        if (vis[v]) continue;\n        vis[v] = true;\n        out.push_back(dirChar(u, v));\n        st.push_back(v);\n    }\n    return out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    globalStart = chrono::steady_clock::now();\n\n    cin >> N >> si >> sj;\n    gridc.resize(N);\n    for (int i = 0; i < N; i++) cin >> gridc[i];\n\n    idg.assign(N, vector<int>(N, -1));\n    rr.clear();\n    cc.clear();\n    cellW.clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (gridc[i][j] != '#') {\n                idg[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                cellW.push_back(gridc[i][j] - '0');\n            }\n        }\n    }\n\n    Rcnt = (int)rr.size();\n    sId = idg[si][sj];\n\n    nbrs.assign(Rcnt, {});\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int i = rr[cid], j = cc[cid];\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) {\n                int nid = idg[ni][nj];\n                if (nid != -1) nbrs[cid].push_back(nid);\n            }\n        }\n    }\n    for (int u = 0; u < Rcnt; u++) {\n        sort(nbrs[u].begin(), nbrs[u].end(), [&](int a, int b) {\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    hid.assign(Rcnt, -1);\n    vid.assign(Rcnt, -1);\n    cellsH.clear();\n    cellsV.clear();\n\n    Hcnt = 0;\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (idg[i][j] == -1) {\n                j++;\n                continue;\n            }\n            int h = Hcnt++;\n            cellsH.push_back({});\n            while (j < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                hid[cid] = h;\n                cellsH[h].push_back(cid);\n                j++;\n            }\n        }\n    }\n\n    Vcnt = 0;\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (idg[i][j] == -1) {\n                i++;\n                continue;\n            }\n            int v = Vcnt++;\n            cellsV.push_back({});\n            while (i < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                vid[cid] = v;\n                cellsV[v].push_back(cid);\n                i++;\n            }\n        }\n    }\n\n    adjHFull.assign(Hcnt, {});\n    for (int cid = 0; cid < Rcnt; cid++) {\n        adjHFull[hid[cid]].push_back({vid[cid], cid});\n    }\n\n    dijReady.assign(Rcnt, false);\n    distCache.assign(Rcnt, {});\n    parentCache.assign(Rcnt, {});\n    ensureDijkstra(sId);\n    distStart = distCache[sId];\n\n    bestCellH.assign(Hcnt, -1);\n    bestCellV.assign(Vcnt, -1);\n\n    auto betterCell = [&](int a, int b) {\n        if (a == -1) return true;\n        if (distStart[b] != distStart[a]) return distStart[b] < distStart[a];\n        if (cellW[b] != cellW[a]) return cellW[b] < cellW[a];\n        if (rr[b] != rr[a]) return rr[b] < rr[a];\n        return cc[b] < cc[a];\n    };\n\n    for (int h = 0; h < Hcnt; h++) {\n        for (int cid : cellsH[h]) {\n            if (bestCellH[h] == -1 || betterCell(bestCellH[h], cid)) bestCellH[h] = cid;\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        for (int cid : cellsV[v]) {\n            if (bestCellV[v] == -1 || betterCell(bestCellV[v], cid)) bestCellV[v] = cid;\n        }\n    }\n\n    for (int h = 0; h < Hcnt; h++) {\n        sort(adjHFull[h].begin(), adjHFull[h].end(), [&](auto A, auto B) {\n            int a = A.second, b = B.second;\n            if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    sH = hid[sId];\n    sV = vid[sId];\n\n    activeH.assign(Hcnt, false);\n    activeV.assign(Vcnt, false);\n    adjHRes.assign(Hcnt, {});\n    bool anyResidual = false;\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int h = hid[cid], v = vid[cid];\n        if (h == sH || v == sV) continue;\n        activeH[h] = true;\n        activeV[v] = true;\n        adjHRes[h].push_back({v, cid});\n        anyResidual = true;\n    }\n\n    if (!anyResidual) {\n        cout << '\\n';\n        return 0;\n    }\n\n    vector<ll> segCostH(Hcnt, 0), segCostV(Vcnt, 0);\n    ll sumSeg = 0;\n    int cntSeg = 0;\n    for (int h = 0; h < Hcnt; h++) if (activeH[h]) {\n        segCostH[h] = distStart[bestCellH[h]];\n        sumSeg += segCostH[h];\n        cntSeg++;\n    }\n    for (int v = 0; v < Vcnt; v++) if (activeV[v]) {\n        segCostV[v] = distStart[bestCellV[v]];\n        sumSeg += segCostV[v];\n        cntSeg++;\n    }\n    ll avgSeg = max(1LL, cntSeg ? sumSeg / cntSeg : 1LL);\n\n    string bestPath = buildFallbackDFSRoute();\n    auto [fbok, fbcost] = validateAndCost(bestPath);\n    if (!fbok) {\n        bestPath = \"\";\n        fbcost = INF_LL;\n    }\n    ll bestCost = fbcost;\n\n    vector<pair<vector<char>, vector<char>>> covers;\n    unordered_set<string> seenCover;\n\n    auto addCover = [&](const vector<char>& selH, const vector<char>& selV) {\n        string sig;\n        sig.reserve(Hcnt + Vcnt);\n        for (int h = 0; h < Hcnt; h++) sig.push_back(selH[h] ? '1' : '0');\n        for (int v = 0; v < Vcnt; v++) sig.push_back(selV[v] ? '1' : '0');\n        if (seenCover.insert(sig).second) covers.push_back({selH, selV});\n    };\n\n    auto mvc = buildCanonicalMVC();\n    addCover(mvc.first, mvc.second);\n\n    ll base = sumSeg + 1;\n\n    vector<ll> wH1(Hcnt, 0), wV1(Vcnt, 0);\n    vector<ll> wH2(Hcnt, 0), wV2(Vcnt, 0);\n    vector<ll> wH3(Hcnt, 0), wV3(Vcnt, 0);\n    vector<ll> wH4(Hcnt, 0), wV4(Vcnt, 0);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) {\n            wH1[h] = base + segCostH[h];\n            wH2[h] = 1 + segCostH[h];\n            wH3[h] = avgSeg + segCostH[h];\n            wH4[h] = max(1LL, avgSeg / 2) + segCostH[h];\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) {\n            wV1[v] = base + segCostV[v];\n            wV2[v] = 1 + segCostV[v];\n            wV3[v] = avgSeg + segCostV[v];\n            wV4[v] = max(1LL, avgSeg / 2) + segCostV[v];\n        }\n    }\n\n    auto cv1 = buildWeightedVC(wH1, wV1);\n    auto cv2 = buildWeightedVC(wH2, wV2);\n    auto cv3 = buildWeightedVC(wH3, wV3);\n    auto cv4 = buildWeightedVC(wH4, wV4);\n    addCover(cv1.first, cv1.second);\n    addCover(cv2.first, cv2.second);\n    addCover(cv3.first, cv3.second);\n    addCover(cv4.first, cv4.second);\n\n    {\n        vector<char> allH = activeH, allV(Vcnt, false);\n        addCover(allH, allV);\n    }\n    {\n        vector<char> allH(Hcnt, false), allV = activeV;\n        addCover(allH, allV);\n    }\n\n    struct CandEntry {\n        vector<Task> tasks;\n        int pri;\n        ll est;\n    };\n\n    vector<CandEntry> candidates;\n    unordered_set<string> seenTask;\n\n    auto estimateTasks = [&](const vector<Task>& tasks) {\n        ll s = 0;\n        for (auto &t : tasks) s += distStart[t.cell];\n        s += (ll)tasks.size() * max(1LL, avgSeg / 4);\n        return s;\n    };\n\n    auto addTasks = [&](vector<Task> tasks, int pri) {\n        tasks = compressTasksByCell(tasks);\n        if ((int)tasks.size() > 90) return;\n        string sig = makeTaskSig(tasks);\n        if (seenTask.insert(sig).second) {\n            candidates.push_back({move(tasks), pri, estimateTasks(tasks)});\n        }\n    };\n\n    ll greedyPenaltyA = max(1LL, avgSeg / 5);\n    ll greedyPenaltyB = max(1LL, avgSeg / 2);\n\n    for (int i = 0; i < (int)covers.size(); i++) {\n        addTasks(buildTasksPaired(covers[i].first, covers[i].second), 10 + i);\n\n        if (i < 3) {\n            auto gp1 = buildTasksGreedyPair(covers[i].first, covers[i].second, greedyPenaltyA);\n            if ((int)gp1.size() <= 80) addTasks(move(gp1), 30 + i);\n\n            auto gp2 = buildTasksGreedyPair(covers[i].first, covers[i].second, greedyPenaltyB);\n            if ((int)gp2.size() <= 80) addTasks(move(gp2), 40 + i);\n\n            auto np = buildTasksNoPair(covers[i].first, covers[i].second);\n            if ((int)np.size() <= 65) addTasks(move(np), 60 + i);\n        }\n    }\n\n    sort(candidates.begin(), candidates.end(), [&](const CandEntry& A, const CandEntry& B) {\n        if (A.pri != B.pri) return A.pri < B.pri;\n        if (A.tasks.size() != B.tasks.size()) return A.tasks.size() < B.tasks.size();\n        return A.est < B.est;\n    });\n\n    if ((int)candidates.size() > 12) candidates.resize(12);\n\n    for (auto &ce : candidates) {\n        if (elapsed_ms() > 2770) break;\n        CandidateResult cr = solveCandidate(ce.tasks);\n        if (cr.valid && cr.cost < bestCost) {\n            bestCost = cr.cost;\n            bestPath = move(cr.path);\n        }\n    }\n\n    if (!bestPath.empty() && elapsed_ms() < 2890) {\n        string pruned = pruneLoops(bestPath);\n        auto [okp, cp] = validateAndCost(pruned);\n        if (okp && cp < bestCost) {\n            bestCost = cp;\n            bestPath = move(pruned);\n        }\n    }\n\n    cout << bestPath << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int MAXN = 1000;\nstatic constexpr ll INF64 = (1LL << 62);\nstatic constexpr ll DUMMY_UTILITY = -4'000'000'000'000LL;\n\nstruct Observation {\n    int task;\n    int dur;\n};\n\nstruct Member {\n    int current_task = -1;\n    int start_day = -1;\n    vector<Observation> obs;\n    vector<int> est;\n    bool busy() const { return current_task != -1; }\n};\n\nstruct Solver {\n    int N, M, K, R;\n    vector<vector<int>> req;\n    vector<vector<int>> g;\n    vector<int> indeg_rem;\n    vector<int> state; // 0:not started, 1:in progress, 2:done\n    vector<Member> members;\n\n    vector<int> maxD;\n    vector<double> prior_cap;\n    vector<int> prior_int;\n    vector<double> rank_skill;\n    vector<double> easy_skill;\n\n    vector<int> desc_count;\n    vector<double> avg_proc;\n    vector<double> up_rank;\n    vector<double> base_priority_static;\n    vector<double> global_easy_dur;\n\n    int completed_tasks = 0;\n\n    static double expected_duration_from_w(double w) {\n        if (w <= 0.0) return 1.0;\n        static const double E[5] = {\n            1.0,\n            13.0 / 7.0,\n            17.0 / 7.0,\n            22.0 / 7.0,\n            4.0\n        };\n        if (w < 4.0) {\n            int a = (int)floor(w);\n            double f = w - a;\n            return E[a] * (1.0 - f) + E[a + 1] * f;\n        }\n        return w;\n    }\n\n    double predict_duration_with_skill(const vector<double>& skill, int task) const {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double diff = (double)req[task][k] - skill[k];\n            if (diff > 0) w += diff;\n        }\n        return expected_duration_from_w(w);\n    }\n\n    static pair<int,int> duration_interval(int t) {\n        if (t <= 1) return {0, 4};\n        return {max(1, t - 3), t + 3};\n    }\n\n    void read_input() {\n        cin >> N >> M >> K >> R;\n        req.assign(N, vector<int>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) cin >> req[i][k];\n        }\n        g.assign(N, {});\n        indeg_rem.assign(N, 0);\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            g[u].push_back(v);\n            indeg_rem[v]++;\n        }\n        state.assign(N, 0);\n        members.assign(M, Member{});\n    }\n\n    void preprocess() {\n        maxD.assign(K, 0);\n        vector<double> meanD(K, 0.0);\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                maxD[k] = max(maxD[k], req[i][k]);\n                meanD[k] += req[i][k];\n            }\n        }\n        for (int k = 0; k < K; k++) meanD[k] /= N;\n\n        prior_cap.assign(K, 0.0);\n        prior_int.assign(K, 0);\n        rank_skill.assign(K, 0.0);\n        easy_skill.assign(K, 0.0);\n\n        for (int k = 0; k < K; k++) {\n            double p = 1.6 * meanD[k];\n            p = min<double>(p, maxD[k]);\n            if (p < 0) p = 0;\n            prior_cap[k] = p;\n            prior_int[k] = (int)llround(p);\n            prior_int[k] = max(0, min(prior_int[k], maxD[k]));\n            rank_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.75);\n            easy_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.80);\n        }\n\n        for (int j = 0; j < M; j++) {\n            members[j].est = prior_int;\n        }\n\n        // Exact descendant counts with bitset.\n        vector<bitset<MAXN>> reach(N);\n        desc_count.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            bitset<MAXN> bs;\n            for (int to : g[i]) {\n                bs |= reach[to];\n                bs.set(to);\n            }\n            reach[i] = bs;\n            desc_count[i] = (int)bs.count();\n        }\n\n        avg_proc.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            avg_proc[i] = predict_duration_with_skill(rank_skill, i);\n        }\n\n        up_rank.assign(N, 0.0);\n        for (int i = N - 1; i >= 0; i--) {\n            double mx = 0.0;\n            for (int to : g[i]) mx = max(mx, up_rank[to]);\n            up_rank[i] = avg_proc[i] + mx;\n        }\n\n        base_priority_static.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            base_priority_static[i] = up_rank[i] + 0.03 * desc_count[i];\n        }\n\n        global_easy_dur.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            global_easy_dur[i] = predict_duration_with_skill(easy_skill, i);\n        }\n    }\n\n    void reestimate_member(int j) {\n        auto& mem = members[j];\n        int nobs = (int)mem.obs.size();\n        if (nobs == 0) {\n            mem.est = prior_int;\n            return;\n        }\n        if ((int)mem.est.size() != K) mem.est = prior_int;\n\n        vector<int> s = mem.est;\n        for (int k = 0; k < K; k++) {\n            s[k] = max(0, min(s[k], maxD[k]));\n        }\n\n        vector<int> task_id(nobs), L(nobs), U(nobs);\n        for (int i = 0; i < nobs; i++) {\n            task_id[i] = mem.obs[i].task;\n            auto [l, u] = duration_interval(mem.obs[i].dur);\n            L[i] = l;\n            U[i] = u;\n        }\n\n        vector<int> pred(nobs, 0);\n        for (int i = 0; i < nobs; i++) {\n            int t = task_id[i];\n            int w = 0;\n            for (int k = 0; k < K; k++) {\n                w += max(0, req[t][k] - s[k]);\n            }\n            pred[i] = w;\n        }\n\n        int passes = (nobs < 8 ? 3 : 2);\n        double reg = 10.0 / (nobs + 3.0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            for (int k = 0; k < K; k++) {\n                int old = s[k];\n                int lim = maxD[k];\n\n                vector<int> dk(nobs), oldPart(nobs);\n                for (int i = 0; i < nobs; i++) {\n                    int dkk = req[task_id[i]][k];\n                    dk[i] = dkk;\n                    oldPart[i] = max(0, dkk - old);\n                }\n\n                double bestObj = 1e100;\n                int bestX = old;\n\n                for (int x = 0; x <= lim; x++) {\n                    double obj = reg * (x - prior_int[k]) * (x - prior_int[k]);\n                    for (int i = 0; i < nobs; i++) {\n                        int w = pred[i] - oldPart[i] + max(0, dk[i] - x);\n                        if (w < L[i]) {\n                            double d = (double)(L[i] - w);\n                            obj += d * d;\n                        } else if (w > U[i]) {\n                            double d = (double)(w - U[i]);\n                            obj += d * d;\n                        }\n                    }\n                    if (obj < bestObj) {\n                        bestObj = obj;\n                        bestX = x;\n                    }\n                }\n\n                if (bestX != old) {\n                    for (int i = 0; i < nobs; i++) {\n                        pred[i] = pred[i] - oldPart[i] + max(0, dk[i] - bestX);\n                    }\n                    s[k] = bestX;\n                }\n            }\n        }\n\n        mem.est = s;\n    }\n\n    vector<int> hungarian_min(const vector<vector<ll>>& cost) {\n        int n = (int)cost.size();\n        int m = (int)cost[0].size();\n        // Requires n <= m\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF64);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF64;\n                for (int j = 1; j <= m; j++) {\n                    if (used[j]) continue;\n                    ll cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0 != 0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    vector<pair<int,int>> choose_assignments(int day) {\n        vector<int> free_members, ready_tasks;\n        for (int j = 0; j < M; j++) if (!members[j].busy()) free_members.push_back(j);\n        for (int i = 0; i < N; i++) if (state[i] == 0 && indeg_rem[i] == 0) ready_tasks.push_back(i);\n\n        if (free_members.empty() || ready_tasks.empty()) return {};\n\n        vector<vector<double>> eff_skill(M, vector<double>(K, 0.0));\n        for (int j = 0; j < M; j++) {\n            double conf = (double)members[j].obs.size() / (members[j].obs.size() + 5.0);\n            for (int k = 0; k < K; k++) {\n                eff_skill[j][k] = conf * members[j].est[k] + (1.0 - conf) * prior_cap[k];\n            }\n        }\n\n        vector<double> dynP(N, -1e100);\n        vector<pair<double,int>> order;\n        order.reserve(ready_tasks.size());\n\n        for (int task : ready_tasks) {\n            double unlock_bonus = 0.0;\n            for (int to : g[task]) {\n                if (state[to] == 0 && indeg_rem[to] == 1) {\n                    unlock_bonus += base_priority_static[to];\n                }\n            }\n            double p = base_priority_static[task] + 0.15 * unlock_bonus - 1e-4 * task;\n            dynP[task] = p;\n            order.push_back({p, task});\n        }\n\n        sort(order.begin(), order.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        auto raw_pred = [&](int member, int task) -> double {\n            return predict_duration_with_skill(eff_skill[member], task);\n        };\n\n        vector<char> used_member(M, false), used_task(N, false);\n        vector<pair<int,int>> res;\n\n        int urgent = 0;\n        if ((int)free_members.size() >= 2) {\n            urgent = min<int>((int)free_members.size(), (completed_tasks < 2 * M ? 2 : 3));\n        }\n\n        int ptr = 0;\n        while (urgent > 0 && ptr < (int)order.size()) {\n            int task = order[ptr++].second;\n            if (used_task[task]) continue;\n\n            double bestDur = 1e100;\n            int bestMember = -1;\n            for (int j : free_members) {\n                if (used_member[j]) continue;\n                double d = raw_pred(j, task);\n                if (d < bestDur - 1e-12 || (abs(d - bestDur) <= 1e-12 && j < bestMember)) {\n                    bestDur = d;\n                    bestMember = j;\n                }\n            }\n            if (bestMember == -1) break;\n\n            used_member[bestMember] = true;\n            used_task[task] = true;\n            res.push_back({bestMember, task});\n            urgent--;\n        }\n\n        vector<int> rem_members;\n        for (int j : free_members) if (!used_member[j]) rem_members.push_back(j);\n\n        vector<int> rem_tasks_order;\n        for (auto [p, t] : order) if (!used_task[t]) rem_tasks_order.push_back(t);\n\n        if (rem_members.empty() || rem_tasks_order.empty()) return res;\n\n        vector<int> cand;\n        vector<char> chosen(N, false);\n\n        if ((int)rem_tasks_order.size() <= 80) {\n            cand = rem_tasks_order;\n            for (int t : cand) chosen[t] = true;\n        } else {\n            const int TOP_PRIO = 50;\n            const int TOP_EASY = 25;\n\n            for (int i = 0; i < (int)rem_tasks_order.size() && (int)cand.size() < TOP_PRIO; i++) {\n                int t = rem_tasks_order[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            vector<int> easy = rem_tasks_order;\n            sort(easy.begin(), easy.end(), [&](int a, int b) {\n                if (global_easy_dur[a] != global_easy_dur[b]) return global_easy_dur[a] < global_easy_dur[b];\n                if (dynP[a] != dynP[b]) return dynP[a] > dynP[b];\n                return a < b;\n            });\n\n            for (int i = 0; i < (int)easy.size() && i < TOP_EASY; i++) {\n                int t = easy[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            int need = min<int>((int)rem_tasks_order.size(), max<int>((int)rem_members.size(), 20));\n            for (int t : rem_tasks_order) {\n                if ((int)cand.size() >= need) break;\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n        }\n\n        if (cand.empty()) return res;\n\n        int n = (int)rem_members.size();\n        int m = (int)cand.size() + n; // add dummy columns\n        vector<vector<ll>> util(n, vector<ll>(m, DUMMY_UTILITY));\n\n        for (int r = 0; r < n; r++) {\n            int member = rem_members[r];\n            int oc = (int)members[member].obs.size();\n            for (int c = 0; c < (int)cand.size(); c++) {\n                int task = cand[c];\n                double dur = raw_pred(member, task);\n\n                if (oc == 0) {\n                    if (completed_tasks < M) dur *= 2.2;\n                    else if (completed_tasks < 3 * M) dur *= 1.6;\n                } else if (oc == 1 && completed_tasks < 3 * M) {\n                    dur *= 1.2;\n                }\n\n                double u = dynP[task] * 1200.0 - dur * 800.0;\n                util[r][c] = llround(u);\n            }\n        }\n\n        ll maxU = DUMMY_UTILITY;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                maxU = max(maxU, util[i][j]);\n            }\n        }\n\n        vector<vector<ll>> cost(n, vector<ll>(m));\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                cost[i][j] = maxU - util[i][j];\n            }\n        }\n\n        vector<int> assign = hungarian_min(cost);\n        for (int r = 0; r < n; r++) {\n            int c = assign[r];\n            if (0 <= c && c < (int)cand.size()) {\n                res.push_back({rem_members[r], cand[c]});\n            }\n        }\n\n        return res;\n    }\n\n    void run() {\n        read_input();\n        preprocess();\n\n        for (int day = 1; ; day++) {\n            auto assignments = choose_assignments(day);\n\n            // Apply assignments locally before output.\n            for (auto [j, t] : assignments) {\n                members[j].current_task = t;\n                members[j].start_day = day;\n                state[t] = 1;\n            }\n\n            cout << assignments.size();\n            for (auto [j, t] : assignments) {\n                cout << ' ' << (j + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int ncomp;\n            if (!(cin >> ncomp)) return;\n            if (ncomp == -1) return;\n\n            vector<int> finished_members(ncomp);\n            for (int i = 0; i < ncomp; i++) {\n                cin >> finished_members[i];\n                --finished_members[i];\n            }\n\n            vector<int> completed_today_tasks;\n            completed_today_tasks.reserve(ncomp);\n\n            for (int j : finished_members) {\n                if (j < 0 || j >= M) continue;\n                if (!members[j].busy()) continue;\n\n                int task = members[j].current_task;\n                int dur = day - members[j].start_day + 1;\n\n                members[j].obs.push_back({task, dur});\n                members[j].current_task = -1;\n                members[j].start_day = -1;\n\n                if (0 <= task && task < N && state[task] == 1) {\n                    state[task] = 2;\n                    completed_today_tasks.push_back(task);\n                    completed_tasks++;\n                }\n\n                reestimate_member(j);\n            }\n\n            for (int task : completed_today_tasks) {\n                for (int to : g[task]) {\n                    if (state[to] == 0) {\n                        indeg_rem[to]--;\n                    }\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing u8 = unsigned char;\nusing u16 = uint16_t;\nusing u64 = uint64_t;\n\nstatic constexpr int N = 1000;\nstatic constexpr int M = 50;\nstatic constexpr int POINTS = 2 * N + 1; // 0..1999: pickups/deliveries, 2000: depot\nstatic constexpr int DEPOT = 2000;\nstatic constexpr int DEPOT_X = 400;\nstatic constexpr int DEPOT_Y = 400;\nstatic constexpr int MAX_ROUTE = 110;\nstatic constexpr int INF = 1e9;\n\nstatic u16 distMat[POINTS][POINTS];\nstatic int PX[POINTS], PY[POINTS];\n\nchrono::steady_clock::time_point g_start;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int pick_pid(int oid) { return oid << 1; }\ninline int del_pid(int oid) { return (oid << 1) | 1; }\n\nstruct Insertion {\n    int delta;\n    int gapP;\n    int gapD;\n    bool sameGap;\n};\n\nstruct Candidate {\n    int delta;\n    int oid;\n    Insertion ins;\n};\n\nstruct RouteContext {\n    int L = 0;\n    int E = 0;\n    int pid[MAX_ROUTE];\n    int edge[MAX_ROUTE];\n    int total = 0;\n};\n\nstruct Solution {\n    vector<int> route;       // point ids, includes depot at both ends\n    array<u8, N> sel{};\n    int cost = INF;\n};\n\nstatic inline u64 splitmix64(u64 x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\ninline int calc_cost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distMat[route[i]][route[i + 1]];\n    }\n    return s;\n}\n\ninline void build_context(const vector<int>& route, RouteContext& ctx) {\n    ctx.L = (int)route.size();\n    ctx.E = ctx.L - 1;\n    ctx.total = 0;\n    for (int i = 0; i < ctx.L; i++) ctx.pid[i] = route[i];\n    for (int i = 0; i < ctx.E; i++) {\n        ctx.edge[i] = distMat[ctx.pid[i]][ctx.pid[i + 1]];\n        ctx.total += ctx.edge[i];\n    }\n}\n\n// O(route length) best feasible insertion of one order.\ninline Insertion find_best_insertion(const RouteContext& ctx, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n    const u16* Dp = distMat[p];\n    const u16* Dd = distMat[d];\n    const int pd = Dp[d];\n\n    int delCost[MAX_ROUTE];\n    int suffMin[MAX_ROUTE];\n    int suffArg[MAX_ROUTE];\n\n    for (int j = 0; j < ctx.E; j++) {\n        const int u = ctx.pid[j];\n        const int v = ctx.pid[j + 1];\n        delCost[j] = (int)Dd[u] + (int)Dd[v] - ctx.edge[j];\n    }\n\n    suffMin[ctx.E] = INF;\n    suffArg[ctx.E] = -1;\n    for (int j = ctx.E - 1; j >= 0; j--) {\n        if (delCost[j] <= suffMin[j + 1]) {\n            suffMin[j] = delCost[j];\n            suffArg[j] = j;\n        } else {\n            suffMin[j] = suffMin[j + 1];\n            suffArg[j] = suffArg[j + 1];\n        }\n    }\n\n    Insertion best{INF, -1, -1, true};\n\n    for (int i = 0; i < ctx.E; i++) {\n        const int u = ctx.pid[i];\n        const int v = ctx.pid[i + 1];\n\n        int same = (int)Dp[u] + pd + (int)Dd[v] - ctx.edge[i];\n        if (same < best.delta) {\n            best = Insertion{same, i, i, true};\n        }\n\n        if (i + 1 < ctx.E) {\n            int pickCost = (int)Dp[u] + (int)Dp[v] - ctx.edge[i];\n            int later = pickCost + suffMin[i + 1];\n            if (later < best.delta) {\n                best = Insertion{later, i, suffArg[i + 1], false};\n            }\n        }\n    }\n\n    return best;\n}\n\ninline vector<int> apply_insertion(const vector<int>& route, int oid, const Insertion& ins) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n\n    vector<int> res;\n    res.reserve(route.size() + 2);\n\n    for (int i = 0; i < (int)route.size(); i++) {\n        res.push_back(route[i]);\n        if (i == ins.gapP) {\n            res.push_back(p);\n            if (ins.sameGap) res.push_back(d);\n        }\n        if (!ins.sameGap && i == ins.gapD) {\n            res.push_back(d);\n        }\n    }\n    return res;\n}\n\ninline vector<int> remove_order_from_route(const vector<int>& route, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n    vector<int> res;\n    res.reserve(route.size() - 2);\n    for (int pid : route) {\n        if (pid != p && pid != d) res.push_back(pid);\n    }\n    return res;\n}\n\ninline vector<int> filter_route_without(const vector<int>& route, const array<u8, N>& removed) {\n    vector<int> res;\n    res.reserve(route.size());\n    for (int pid : route) {\n        if (pid == DEPOT) {\n            res.push_back(pid);\n        } else {\n            int oid = pid >> 1;\n            if (!removed[oid]) res.push_back(pid);\n        }\n    }\n    return res;\n}\n\ninline vector<int> selected_ids_from_route(const vector<int>& route) {\n    vector<int> ids;\n    ids.reserve(M);\n    for (int pid : route) {\n        if (pid != DEPOT && (pid & 1) == 0) ids.push_back(pid >> 1);\n    }\n    return ids;\n}\n\ninline void compute_positions(const vector<int>& route, array<int, N>& posP, array<int, N>& posD) {\n    posP.fill(-1);\n    posD.fill(-1);\n    for (int i = 0; i < (int)route.size(); i++) {\n        int pid = route[i];\n        if (pid == DEPOT) continue;\n        int oid = pid >> 1;\n        if ((pid & 1) == 0) posP[oid] = i;\n        else posD[oid] = i;\n    }\n}\n\ninline int exact_removal_saving(const vector<int>& route, int ip, int id) {\n    if (ip > id) swap(ip, id);\n    if (id == ip + 1) {\n        int a = route[ip - 1], b = route[ip], c = route[id], d = route[id + 1];\n        return (int)distMat[a][b] + (int)distMat[b][c] + (int)distMat[c][d] - (int)distMat[a][d];\n    } else {\n        int a = route[ip - 1], b = route[ip], c = route[ip + 1];\n        int e = route[id - 1], f = route[id], g = route[id + 1];\n        return ((int)distMat[a][b] + (int)distMat[b][c] - (int)distMat[a][c]) +\n               ((int)distMat[e][f] + (int)distMat[f][g] - (int)distMat[e][g]);\n    }\n}\n\ninline void add_candidate(vector<Candidate>& bests, const Candidate& c, int K) {\n    int pos = 0;\n    while (pos < (int)bests.size() && bests[pos].delta <= c.delta) ++pos;\n    if (pos >= K) return;\n    bests.insert(bests.begin() + pos, c);\n    if ((int)bests.size() > K) bests.pop_back();\n}\n\ninline int pick_rcl_index(int sz, mt19937& rng) {\n    if (sz <= 1) return 0;\n    static const int W[12] = {32, 20, 14, 10, 8, 6, 4, 3, 2, 1, 1, 1};\n    int sum = 0;\n    for (int i = 0; i < sz; i++) sum += W[i];\n    int r = (int)(rng() % sum);\n    for (int i = 0; i < sz; i++) {\n        if (r < W[i]) return i;\n        r -= W[i];\n    }\n    return sz - 1;\n}\n\nSolution construct_solution(int seedOid, int rclK, mt19937& rng) {\n    Solution sol;\n    sol.route = {DEPOT, DEPOT};\n    sol.sel.fill(0);\n    sol.cost = 0;\n    int cnt = 0;\n\n    if (seedOid != -1) {\n        int p = pick_pid(seedOid);\n        int d = del_pid(seedOid);\n        sol.route = {DEPOT, p, d, DEPOT};\n        sol.sel[seedOid] = 1;\n        sol.cost = distMat[DEPOT][p] + distMat[p][d] + distMat[d][DEPOT];\n        cnt = 1;\n    }\n\n    for (; cnt < M; cnt++) {\n        RouteContext ctx;\n        build_context(sol.route, ctx);\n\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n    }\n\n    return sol;\n}\n\n// Remove one whole order and reinsert it optimally.\nbool best_pair_reinsert_once(Solution& sol, double deadline) {\n    vector<int> ids = selected_ids_from_route(sol.route);\n\n    int bestCost = sol.cost;\n    int bestOid = -1;\n    Insertion bestIns{};\n    vector<int> bestBase;\n\n    for (int t = 0; t < (int)ids.size(); t++) {\n        if ((t & 7) == 0 && elapsed_sec() > deadline) break;\n        int oid = ids[t];\n        vector<int> base = remove_order_from_route(sol.route, oid);\n        RouteContext ctx;\n        build_context(base, ctx);\n        Insertion ins = find_best_insertion(ctx, oid);\n        int nc = ctx.total + ins.delta;\n        if (nc < bestCost) {\n            bestCost = nc;\n            bestOid = oid;\n            bestIns = ins;\n            bestBase = move(base);\n        }\n    }\n\n    if (bestOid == -1) return false;\n    sol.route = apply_insertion(bestBase, bestOid, bestIns);\n    sol.cost = bestCost;\n    return true;\n}\n\n// Cheap route polishing: swap adjacent nodes if precedence remains valid.\nbool best_adjacent_swap_once(Solution& sol, double deadline) {\n    const vector<int>& route = sol.route;\n    int L = (int)route.size();\n    if (L <= 3) return false;\n\n    array<int, N> posP, posD;\n    compute_positions(route, posP, posD);\n\n    int bestDelta = 0;\n    int bestI = -1;\n\n    for (int i = 1; i + 2 < L; i++) {\n        if ((i & 15) == 0 && elapsed_sec() > deadline) break;\n\n        int x = route[i];\n        int y = route[i + 1];\n        int ox = x >> 1;\n        int oy = y >> 1;\n\n        int pox = posP[ox], dox = posD[ox];\n        int poy = posP[oy], doy = posD[oy];\n\n        if ((x & 1) == 0) pox = i + 1;\n        else dox = i + 1;\n\n        if ((y & 1) == 0) poy = i;\n        else doy = i;\n\n        bool ok;\n        if (ox == oy) ok = (pox < dox);\n        else ok = (pox < dox) && (poy < doy);\n        if (!ok) continue;\n\n        int a = route[i - 1];\n        int b = route[i + 2];\n        int oldCost = (int)distMat[a][x] + (int)distMat[x][y] + (int)distMat[y][b];\n        int newCost = (int)distMat[a][y] + (int)distMat[y][x] + (int)distMat[x][b];\n        int delta = newCost - oldCost;\n\n        if (delta < bestDelta) {\n            bestDelta = delta;\n            bestI = i;\n        }\n    }\n\n    if (bestI == -1) return false;\n    swap(sol.route[bestI], sol.route[bestI + 1]);\n    sol.cost += bestDelta;\n    return true;\n}\n\n// More expensive move: relocate one pickup or one delivery while preserving precedence.\nbool best_node_relocate_once(Solution& sol, double deadline) {\n    const vector<int>& route = sol.route;\n    int L = (int)route.size();\n\n    array<int, N> posP, posD;\n    compute_positions(route, posP, posD);\n\n    int bestDelta = 0;\n    int bestI = -1;\n    int bestGap = -1;\n\n    for (int i = 1; i + 1 < L; i++) {\n        if ((i & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int pid = route[i];\n        int oid = pid >> 1;\n        bool isPickup = ((pid & 1) == 0);\n\n        vector<int> rem;\n        rem.reserve(L - 1);\n        for (int k = 0; k < L; k++) {\n            if (k != i) rem.push_back(route[k]);\n        }\n\n        int len = (int)rem.size();\n        int otherPos = isPickup ? posD[oid] : posP[oid];\n        int otherPosRem = otherPos - (otherPos > i ? 1 : 0);\n\n        int lo = 0, hi = len - 2;\n        if (isPickup) {\n            hi = otherPosRem - 1;\n        } else {\n            lo = otherPosRem;\n        }\n        if (lo > hi) continue;\n\n        int remSaving =\n            (int)distMat[route[i - 1]][pid] +\n            (int)distMat[pid][route[i + 1]] -\n            (int)distMat[route[i - 1]][route[i + 1]];\n\n        for (int g = lo; g <= hi; g++) {\n            int u = rem[g];\n            int v = rem[g + 1];\n            int insCost =\n                (int)distMat[u][pid] +\n                (int)distMat[pid][v] -\n                (int)distMat[u][v];\n            int delta = -remSaving + insCost;\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestI = i;\n                bestGap = g;\n            }\n        }\n    }\n\n    if (bestI == -1) return false;\n\n    int pid = sol.route[bestI];\n    vector<int> rem;\n    rem.reserve(sol.route.size() - 1);\n    for (int k = 0; k < (int)sol.route.size(); k++) {\n        if (k != bestI) rem.push_back(sol.route[k]);\n    }\n\n    vector<int> res;\n    res.reserve(sol.route.size());\n    for (int k = 0; k < (int)rem.size(); k++) {\n        res.push_back(rem[k]);\n        if (k == bestGap) res.push_back(pid);\n    }\n\n    sol.route.swap(res);\n    sol.cost += bestDelta;\n    return true;\n}\n\n// Replace one selected order with one unselected order.\nbool best_single_replace_once(Solution& sol, double deadline) {\n    vector<int> selIds = selected_ids_from_route(sol.route);\n\n    int bestCost = sol.cost;\n    int remOid = -1, addOid = -1;\n    Insertion bestIns{};\n    vector<int> bestBase;\n\n    for (int si = 0; si < (int)selIds.size(); si++) {\n        if ((si & 3) == 0 && elapsed_sec() > deadline) break;\n\n        int x = selIds[si];\n        vector<int> base = remove_order_from_route(sol.route, x);\n        RouteContext ctx;\n        build_context(base, ctx);\n\n        int localBestCost = INF;\n        int bestY = -1;\n        Insertion localIns{};\n\n        for (int y = 0; y < N; y++) {\n            if (sol.sel[y]) continue;\n            Insertion ins = find_best_insertion(ctx, y);\n            int c = ctx.total + ins.delta;\n            if (c < localBestCost) {\n                localBestCost = c;\n                bestY = y;\n                localIns = ins;\n            }\n        }\n\n        if (localBestCost < bestCost) {\n            bestCost = localBestCost;\n            remOid = x;\n            addOid = bestY;\n            bestIns = localIns;\n            bestBase = move(base);\n        }\n    }\n\n    if (remOid == -1) return false;\n\n    sol.sel[remOid] = 0;\n    sol.sel[addOid] = 1;\n    sol.route = apply_insertion(bestBase, addOid, bestIns);\n    sol.cost = bestCost;\n    return true;\n}\n\nvector<int> choose_removals(const Solution& sol, int mode, int K, mt19937& rng) {\n    K = min(K, M);\n    vector<int> selIds = selected_ids_from_route(sol.route);\n\n    vector<int> res;\n    res.reserve(K);\n    array<u8, N> used{};\n    used.fill(0);\n\n    auto add_oid = [&](int oid) {\n        if (!used[oid]) {\n            used[oid] = 1;\n            res.push_back(oid);\n        }\n    };\n\n    if (mode == 0) {\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int i = 0; i < K; i++) add_oid(selIds[i]);\n    } else if (mode == 1) {\n        array<int, N> posP, posD;\n        compute_positions(sol.route, posP, posD);\n        vector<pair<int, int>> sav;\n        sav.reserve(M);\n        for (int oid : selIds) {\n            int s = exact_removal_saving(sol.route, posP[oid], posD[oid]);\n            sav.push_back({s, oid});\n        }\n        sort(sav.rbegin(), sav.rend());\n        for (int i = 0; i < K; i++) add_oid(sav[i].second);\n    } else if (mode == 2) {\n        int L = (int)sol.route.size();\n        int st = 1 + (int)(rng() % (L - 2));\n        int span = min(L - 2, st + 2 * K + 6);\n        for (int i = st; i <= span && (int)res.size() < K; i++) {\n            int pid = sol.route[i];\n            if (pid != DEPOT) add_oid(pid >> 1);\n        }\n        if ((int)res.size() < K) {\n            shuffle(selIds.begin(), selIds.end(), rng);\n            for (int oid : selIds) {\n                if ((int)res.size() >= K) break;\n                add_oid(oid);\n            }\n        }\n    } else if (mode == 3) {\n        int base = selIds[(int)(rng() % selIds.size())];\n        int bp = pick_pid(base), bd = del_pid(base);\n        vector<pair<int, int>> sim;\n        sim.reserve(M);\n        for (int oid : selIds) {\n            int s = (int)distMat[bp][pick_pid(oid)] + (int)distMat[bd][del_pid(oid)];\n            s += (int)(rng() % 50);\n            sim.push_back({s, oid});\n        }\n        sort(sim.begin(), sim.end());\n        for (int i = 0; i < K; i++) add_oid(sim[i].second);\n    } else {\n        array<int, N> posP, posD;\n        compute_positions(sol.route, posP, posD);\n        vector<pair<int, int>> sav;\n        sav.reserve(M);\n        for (int oid : selIds) {\n            int s = exact_removal_saving(sol.route, posP[oid], posD[oid]);\n            sav.push_back({s, oid});\n        }\n        sort(sav.rbegin(), sav.rend());\n        int takeW = max(1, K / 2);\n        for (int i = 0; i < takeW; i++) add_oid(sav[i].second);\n\n        int base = selIds[(int)(rng() % selIds.size())];\n        int bp = pick_pid(base), bd = del_pid(base);\n        vector<pair<int, int>> sim;\n        sim.reserve(M);\n        for (int oid : selIds) {\n            int s = (int)distMat[bp][pick_pid(oid)] + (int)distMat[bd][del_pid(oid)];\n            s += (int)(rng() % 50);\n            sim.push_back({s, oid});\n        }\n        sort(sim.begin(), sim.end());\n        for (auto& [_, oid] : sim) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int oid : selIds) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n    }\n\n    return res;\n}\n\nSolution destroy_repair(const Solution& base, int mode, int K, int rclK, bool forbidRemoved, mt19937& rng) {\n    vector<int> rem = choose_removals(base, mode, K, rng);\n\n    Solution sol;\n    sol.sel = base.sel;\n\n    array<u8, N> removed{};\n    removed.fill(0);\n    array<u8, N> banned{};\n    banned.fill(0);\n\n    for (int oid : rem) {\n        removed[oid] = 1;\n        if (forbidRemoved) banned[oid] = 1;\n        sol.sel[oid] = 0;\n    }\n\n    sol.route = filter_route_without(base.route, removed);\n    RouteContext ctx;\n    build_context(sol.route, ctx);\n    sol.cost = ctx.total;\n\n    int cnt = M - (int)rem.size();\n    while (cnt < M) {\n        build_context(sol.route, ctx);\n\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            if (banned[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        if (bests.empty()) {\n            for (int oid = 0; oid < N; oid++) banned[oid] = 0;\n            for (int oid = 0; oid < N; oid++) {\n                if (sol.sel[oid]) continue;\n                Insertion ins = find_best_insertion(ctx, oid);\n                add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n            }\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n        cnt++;\n    }\n\n    return sol;\n}\n\ninline double rand01(mt19937& rng) {\n    return double(rng()) * (1.0 / 4294967296.0);\n}\n\n// Main-loop optimizer: cheap and robust.\nvoid local_opt_search(Solution& sol, double deadline, int maxReplace) {\n    int rep = 0;\n    while (elapsed_sec() < deadline) {\n        if (best_pair_reinsert_once(sol, deadline)) continue;\n        if (best_adjacent_swap_once(sol, deadline)) continue;\n        if (rep < maxReplace && best_single_replace_once(sol, deadline)) {\n            rep++;\n            continue;\n        }\n        break;\n    }\n}\n\n// Final intensification: includes expensive single-node relocate.\nvoid local_opt_final(Solution& sol, double deadline, int maxReplace) {\n    int rep = 0;\n    while (elapsed_sec() < deadline) {\n        if (best_pair_reinsert_once(sol, deadline)) continue;\n        if (best_adjacent_swap_once(sol, deadline)) continue;\n        if (best_node_relocate_once(sol, deadline)) continue;\n        if (rep < maxReplace && best_single_replace_once(sol, deadline)) {\n            rep++;\n            continue;\n        }\n        break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    u64 h = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        PX[pick_pid(i)] = a;\n        PY[pick_pid(i)] = b;\n        PX[del_pid(i)] = c;\n        PY[del_pid(i)] = d;\n        h = splitmix64(h ^ (u64)(a + 1009 * b + 9176 * c + 65537 * d + i * 1315423911u));\n    }\n    PX[DEPOT] = DEPOT_X;\n    PY[DEPOT] = DEPOT_Y;\n\n    g_start = chrono::steady_clock::now();\n\n    for (int i = 0; i < POINTS; i++) {\n        for (int j = 0; j < POINTS; j++) {\n            distMat[i][j] = (u16)(abs(PX[i] - PX[j]) + abs(PY[i] - PY[j]));\n        }\n    }\n\n    mt19937 rng((uint32_t)(h ^ (h >> 32)));\n\n    vector<pair<int, int>> centerRank;\n    centerRank.reserve(N);\n    for (int oid = 0; oid < N; oid++) {\n        int p = pick_pid(oid), d = del_pid(oid);\n        int sc = (int)distMat[DEPOT][p] + (int)distMat[p][d] + (int)distMat[d][DEPOT];\n        centerRank.push_back({sc, oid});\n    }\n    sort(centerRank.begin(), centerRank.end());\n\n    vector<int> seedPool;\n    for (int i = 0; i < min(250, N); i++) seedPool.push_back(centerRank[i].second);\n\n    const double INIT_DEADLINE = 0.50;\n    const double SEARCH_DEADLINE = 1.86;\n    const double FINAL_DEADLINE = 1.97;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto update_best = [&](Solution&& sol) {\n        if (!hasBest || sol.cost < best.cost) {\n            best = move(sol);\n            hasBest = true;\n        }\n    };\n\n    // Deterministic / semi-deterministic initial constructions.\n    {\n        Solution sol = construct_solution(-1, 1, rng);\n        local_opt_search(sol, INIT_DEADLINE, 1);\n        update_best(move(sol));\n    }\n\n    for (int i = 0; i < 4 && elapsed_sec() < INIT_DEADLINE; i++) {\n        Solution sol = construct_solution(seedPool[i], 1, rng);\n        local_opt_search(sol, INIT_DEADLINE, 1);\n        update_best(move(sol));\n    }\n\n    // Randomized multistarts.\n    while (elapsed_sec() < INIT_DEADLINE) {\n        int seed = ((rng() & 3) == 0 ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 120))]);\n        int rcl = 5 + (int)(rng() % 6); // 5..10\n        Solution sol = construct_solution(seed, rcl, rng);\n        if ((rng() & 1) == 0) {\n            if ((rng() & 1) == 0) best_pair_reinsert_once(sol, INIT_DEADLINE);\n            else best_adjacent_swap_once(sol, INIT_DEADLINE);\n        }\n        update_best(move(sol));\n    }\n\n    Solution current = best;\n    int iter = 0;\n    int stagn = 0;\n\n    while (elapsed_sec() < SEARCH_DEADLINE) {\n        if ((iter % 12) == 0) {\n            local_opt_search(current, SEARCH_DEADLINE, 0);\n            if (current.cost < best.cost) best = current;\n        }\n\n        double progress = max(0.0, min(1.0, (elapsed_sec() - INIT_DEADLINE) / (SEARCH_DEADLINE - INIT_DEADLINE)));\n        double temp = 55.0 * pow(2.0 / 55.0, progress);\n\n        int mode = (int)(rng() % 5);\n        int K = 3 + (int)(rng() % 6); // 3..8\n        if (stagn >= 10) K += 2;\n        if (stagn >= 20) K += 2;\n        if (K > 12) K = 12;\n\n        int rcl = 4 + (int)(rng() % 6); // 4..9\n        bool forbidRemoved = ((rng() % 100) < 80);\n\n        Solution cand = destroy_repair(current, mode, K, rcl, forbidRemoved, rng);\n\n        // Quick polishing: cheap moves first.\n        int coin = (int)(rng() % 100);\n        if (coin < 55) best_pair_reinsert_once(cand, SEARCH_DEADLINE);\n        else if (coin < 90) best_adjacent_swap_once(cand, SEARCH_DEADLINE);\n\n        if ((rng() % 100) < 15) best_node_relocate_once(cand, SEARCH_DEADLINE);\n        if ((rng() % 100) < 8) best_single_replace_once(cand, SEARCH_DEADLINE);\n\n        if (cand.cost < best.cost) {\n            best = cand;\n            local_opt_search(best, SEARCH_DEADLINE, 1);\n            if (best.cost < cand.cost) cand = best;\n            stagn = 0;\n        } else {\n            stagn++;\n        }\n\n        int diff = cand.cost - current.cost;\n        bool accept = false;\n        if (diff <= 0) {\n            accept = true;\n        } else {\n            double prob = exp(-double(diff) / temp);\n            if (rand01(rng) < prob) accept = true;\n        }\n\n        if (accept) current = move(cand);\n\n        if (stagn >= 30 && elapsed_sec() < 1.68) {\n            if (rng() & 1) {\n                current = best;\n            } else {\n                int seed = ((rng() & 1) ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 150))]);\n                current = construct_solution(seed, 8, rng);\n                if ((rng() & 1) == 0) best_pair_reinsert_once(current, SEARCH_DEADLINE);\n                else best_adjacent_swap_once(current, SEARCH_DEADLINE);\n            }\n            stagn = 0;\n        }\n\n        iter++;\n    }\n\n    local_opt_search(best, FINAL_DEADLINE, 3);\n    local_opt_final(best, FINAL_DEADLINE, 8);\n    best.cost = calc_cost(best.route);\n\n    vector<int> ids = selected_ids_from_route(best.route);\n\n    cout << ids.size();\n    for (int oid : ids) cout << ' ' << (oid + 1);\n    cout << '\\n';\n\n    cout << best.route.size();\n    for (int pid : best.route) {\n        cout << ' ' << PX[pid] << ' ' << PY[pid];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p; // negative size for roots\n\n    DSU() {}\n    DSU(int n) : p(n, -1) {}\n\n    int leader(int x) {\n        if (p[x] < 0) return x;\n        return p[x] = leader(p[x]);\n    }\n\n    bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (-p[a] < -p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        return true;\n    }\n};\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nstatic double clamp01(double x) {\n    if (x < 0.0) return 0.0;\n    if (x > 1.0) return 1.0;\n    return x;\n}\n\n// Approximate E[max(path edge lengths)] / mx for the path in the future-MST,\n// assuming each edge length is an independent continuous uniform on [d, 3d].\n// This is used only as a small correction over the robust base threshold.\nstatic double expected_bottleneck_factor(const vector<int>& pathd, int mx) {\n    if (pathd.empty() || mx <= 0) return 2.0;\n\n    // Only edges with 3d > mx can affect the expectation above mx.\n    vector<int> rel;\n    rel.reserve(pathd.size());\n    for (int d : pathd) {\n        if (3 * d > mx) rel.push_back(d);\n    }\n\n    // E[max]/mx = 1 + integral_{x=1..3} P(max >= mx*x) dx\n    // Use Simpson's rule. This is stable enough and cheap.\n    constexpr int SEG = 16; // must be even\n    const double h = 2.0 / SEG;\n\n    auto tail_prob = [&](double x) -> double {\n        double t = mx * x;\n        double prod = 1.0; // product of CDFs\n\n        for (int d : rel) {\n            if (t <= d) {\n                // This edge is always >= t, so max >= t with prob 1.\n                return 1.0;\n            }\n            if (t >= 3.0 * d) {\n                continue; // CDF = 1\n            }\n            prod *= (t - d) / (2.0 * d);\n            if (prod < 1e-15) return 1.0;\n        }\n\n        double ret = 1.0 - prod;\n        if (ret < 0.0) ret = 0.0;\n        if (ret > 1.0) ret = 1.0;\n        return ret;\n    };\n\n    double sum = 0.0;\n    for (int s = 0; s <= SEG; s++) {\n        double x = 1.0 + h * s;\n        int coef = (s == 0 || s == SEG ? 1 : (s & 1 ? 4 : 2));\n        sum += coef * tail_prob(x);\n    }\n    double integral = h * sum / 3.0;\n    double ans = 1.0 + integral;\n\n    if (ans < 2.0) ans = 2.0; // one-edge lower baseline\n    if (ans > 3.0) ans = 3.0;\n    return ans;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> xs[i] >> ys[i];\n    }\n\n    vector<int> U(M), V(M), D(M);\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n        long long dx = xs[U[i]] - xs[V[i]];\n        long long dy = ys[U[i]] - ys[V[i]];\n        D[i] = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n    }\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    DSU adopted(N);\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        int u = U[i], v = V[i];\n        int ans = 0;\n\n        // Already connected by adopted edges => this edge is surely unnecessary.\n        if (!adopted.same(u, v)) {\n            // Compress adopted components.\n            vector<int> root_id(N, -1), cid(N, -1);\n            int C = 0;\n            for (int x = 0; x < N; x++) {\n                int r = adopted.leader(x);\n                if (root_id[r] == -1) root_id[r] = C++;\n                cid[x] = root_id[r];\n            }\n\n            int cu = cid[u], cv = cid[v];\n\n            // Build future-only MST on current components using d as surrogate weight.\n            DSU uf2(C);\n            vector<vector<pair<int,int>>> tree(C); // (to, d)\n            int used = 0;\n            int useful_edges = 0;\n\n            for (int e : ord) {\n                if (e <= i) continue; // future only\n\n                int a = cid[U[e]];\n                int b = cid[V[e]];\n                if (a == b) continue;\n\n                useful_edges++;\n                if (uf2.merge(a, b)) {\n                    tree[a].push_back({b, D[e]});\n                    tree[b].push_back({a, D[e]});\n                    used++;\n                }\n            }\n\n            // If future edges alone cannot connect the current components,\n            // this edge is mandatory.\n            if (used < C - 1) {\n                ans = 1;\n            } else {\n                // Find the path between cu and cv in the future-only MST.\n                vector<int> parent(C, -1), pw(C, 0);\n                queue<int> q;\n                parent[cu] = cu;\n                q.push(cu);\n\n                while (!q.empty() && parent[cv] == -1) {\n                    int x = q.front();\n                    q.pop();\n                    for (auto [to, w] : tree[x]) {\n                        if (parent[to] != -1) continue;\n                        parent[to] = x;\n                        pw[to] = w;\n                        q.push(to);\n                    }\n                }\n\n                vector<int> pathd;\n                int mx = 0;\n                for (int cur = cv; cur != cu; cur = parent[cur]) {\n                    pathd.push_back(pw[cur]);\n                    mx = max(mx, pw[cur]);\n                }\n\n                // Base threshold from the first solution:\n                // denser future graph => more selective,\n                // sparser future graph => more conservative.\n                double density = (C <= 1 ? 10.0 : (double)useful_edges / (double)(C - 1));\n                double t = clamp01((density - 1.0) / 4.0);\n                double lambda_base = 2.05 - 0.45 * t; // [about 1.60, 2.05]\n\n                // Light correction from the expected realized bottleneck on this MST path.\n                // Important: use only as a small adjustment, not as the main rule.\n                double beta = expected_bottleneck_factor(pathd, mx); // in [2,3]\n                double lambda = lambda_base + 0.25 * (beta - 2.0);\n\n                // Small late-stage safety bump when alternatives are scarce.\n                double progress = (double)i / (double)(M - 1);\n                lambda += 0.04 * progress * (1.0 - t);\n\n                if (lambda < 1.55) lambda = 1.55;\n                if (lambda > 2.25) lambda = 2.25;\n\n                ans = ((double)l <= lambda * (double)mx + 1e-9) ? 1 : 0;\n            }\n        } else {\n            ans = 0;\n        }\n\n        cout << ans << '\\n' << flush;\n        if (ans) adopted.merge(u, v);\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int S = 30;\nstatic constexpr int MAX_TURN = 300;\nstatic constexpr int INF = 1e9;\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar moveChar[4] = {'U', 'D', 'L', 'R'};\n\nstruct Task {\n    int wr, wc;\n    int sr, sc;\n    char act;\n};\n\nstruct Door {\n    int wr, wc;\n    int sr, sc;\n    char act;\n};\n\nstruct Room {\n    int r1, r2, c1, c2;\n    int br, bc;\n    int centerR, centerC;\n    array<Door, 2> doors;\n    vector<Task> tasks;\n\n    bool inside(int r, int c) const {\n        return r1 <= r && r <= r2 && c1 <= c && c <= c2;\n    }\n    int area() const {\n        return (r2 - r1 + 1) * (c2 - c1 + 1);\n    }\n};\n\nstruct BFSRes {\n    int dist[S][S];\n    char first[S][S];\n    BFSRes() {\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < S; j++) {\n                dist[i][j] = -1;\n                first[i][j] = 0;\n            }\n        }\n    }\n};\n\nstruct RoomEval {\n    double aggressiveScore = -1e100;\n    double safeScore = -1e100;\n    int insidePets = 0;\n    int insideDogs = 0;\n    int expandedPets = 0;\n    int nearDoorPets = 0;\n    int nearDoorDogs = 0;\n    int sumBest = 0;\n    int tasks = 0;\n};\n\nint N, M;\nvector<pair<int,int>> petsPos;\nvector<int> petsType;\nvector<pair<int,int>> humansPos;\narray<array<bool, S>, S> wallCell;\n\ninline bool inb(int r, int c) {\n    return 0 <= r && r < S && 0 <= c && c < S;\n}\n\nbool is_lower_act(char c) {\n    return c == 'u' || c == 'd' || c == 'l' || c == 'r';\n}\nbool is_upper_act(char c) {\n    return c == 'U' || c == 'D' || c == 'L' || c == 'R';\n}\n\npair<int,int> apply_dir(pair<int,int> p, char ch) {\n    if (ch == 'U' || ch == 'u') return {p.first - 1, p.second};\n    if (ch == 'D' || ch == 'd') return {p.first + 1, p.second};\n    if (ch == 'L' || ch == 'l') return {p.first, p.second - 1};\n    if (ch == 'R' || ch == 'r') return {p.first, p.second + 1};\n    return p;\n}\n\nint count_dogs() {\n    int x = 0;\n    for (int t : petsType) if (t == 4) x++;\n    return x;\n}\n\nRoom make_room(int corner, int H, int W) {\n    // 0 TL, 1 TR, 2 BL, 3 BR\n    bool top = (corner == 0 || corner == 1);\n    bool left = (corner == 0 || corner == 2);\n\n    Room room;\n    if (top) {\n        room.r1 = 0;\n        room.r2 = H - 1;\n        room.br = H;\n    } else {\n        room.r1 = S - H;\n        room.r2 = S - 1;\n        room.br = S - H - 1;\n    }\n\n    if (left) {\n        room.c1 = 0;\n        room.c2 = W - 1;\n        room.bc = W;\n    } else {\n        room.c1 = S - W;\n        room.c2 = S - 1;\n        room.bc = S - W - 1;\n    }\n\n    room.centerR = (room.r1 + room.r2) / 2;\n    room.centerC = (room.c1 + room.c2) / 2;\n\n    int insideRow = top ? room.r2 : room.r1;\n    char hAct = top ? 'd' : 'u';\n\n    int d1 = room.c1 + (W - 1) / 3;\n    int d2 = room.c1 + (2 * (W - 1)) / 3;\n    if (d1 == d2) {\n        if (d2 < room.c2) d2++;\n        else if (d1 > room.c1) d1--;\n    }\n    if (d1 > d2) swap(d1, d2);\n\n    room.doors[0] = Door{room.br, d1, insideRow, d1, hAct};\n    room.doors[1] = Door{room.br, d2, insideRow, d2, hAct};\n\n    room.tasks.clear();\n\n    for (int c = room.c1; c <= room.c2; c++) {\n        if (c == d1 || c == d2) continue;\n        room.tasks.push_back(Task{room.br, c, insideRow, c, hAct});\n    }\n\n    int insideCol = left ? room.c2 : room.c1;\n    char vAct = left ? 'r' : 'l';\n    for (int r = room.r1; r <= room.r2; r++) {\n        room.tasks.push_back(Task{r, room.bc, r, insideCol, vAct});\n    }\n\n    return room;\n}\n\nint dist_to_rect(const Room& room, int r, int c) {\n    int vr = 0, vc = 0;\n    if (r < room.r1) vr = room.r1 - r;\n    else if (r > room.r2) vr = r - room.r2;\n    if (c < room.c1) vc = room.c1 - c;\n    else if (c > room.c2) vc = c - room.c2;\n    return vr + vc;\n}\n\nint nearest_door_dist(const Room& room, int r, int c) {\n    int d0 = abs(r - room.doors[0].wr) + abs(c - room.doors[0].wc);\n    int d1 = abs(r - room.doors[1].wr) + abs(c - room.doors[1].wc);\n    return min(d0, d1);\n}\n\nRoomEval evaluate_room(const Room& room) {\n    RoomEval e;\n    int dogCnt = count_dogs();\n    int reqBase = max(1, M - (dogCnt > 0 ? 1 : 0));\n\n    e.tasks = (int)room.tasks.size();\n\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        if (room.inside(r, c)) {\n            e.insidePets++;\n            if (petsType[i] == 4) e.insideDogs++;\n        }\n        if (room.r1 - 1 <= r && r <= room.r2 + 1 &&\n            room.c1 - 1 <= c && c <= room.c2 + 1) {\n            e.expandedPets++;\n        }\n        int dd = nearest_door_dist(room, r, c);\n        if (dd <= 3) e.nearDoorPets += (4 - dd);\n        if (petsType[i] == 4 && dd <= 6) e.nearDoorDogs += (7 - dd);\n    }\n\n    vector<int> hdist;\n    hdist.reserve(M);\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = humansPos[i];\n        hdist.push_back(dist_to_rect(room, r, c));\n    }\n    sort(hdist.begin(), hdist.end());\n    for (int i = 0; i < min(reqBase, (int)hdist.size()); i++) e.sumBest += hdist[i];\n\n    {\n        double score = 0.0;\n        score += 5000.0 * room.area();\n        score -= 35.0 * e.sumBest;\n        score -= 100.0 * e.tasks;\n        score -= 250.0 * e.expandedPets;\n        score -= 700.0 * e.nearDoorPets;\n        score -= 1400.0 * e.nearDoorDogs;\n        if (e.insidePets == 0) score += 5e6;\n        score -= 2.3e6 * e.insidePets;\n        score -= 1.5e6 * e.insideDogs;\n        e.aggressiveScore = score;\n    }\n\n    {\n        double score = 0.0;\n        score += 2600.0 * room.area();\n        score -= 60.0 * e.sumBest;\n        score -= 185.0 * e.tasks;\n        score -= 650.0 * e.expandedPets;\n        score -= 1250.0 * e.nearDoorPets;\n        score -= 2900.0 * e.nearDoorDogs;\n        if (e.insidePets == 0) score += 6.2e6;\n        score -= 3.4e6 * e.insidePets;\n        score -= 2.6e6 * e.insideDogs;\n        e.safeScore = score;\n    }\n\n    return e;\n}\n\nRoom choose_room() {\n    Room bestAgg = make_room(0, 8, 8);\n    Room bestSafe = make_room(0, 6, 6);\n    RoomEval bestAggEval, bestSafeEval;\n    double bestAggScore = -1e100;\n    double bestSafeScore = -1e100;\n\n    for (int H = 5; H <= 14; H++) {\n        for (int W = 5; W <= 14; W++) {\n            for (int corner = 0; corner < 4; corner++) {\n                Room room = make_room(corner, H, W);\n                RoomEval e = evaluate_room(room);\n                if (e.aggressiveScore > bestAggScore) {\n                    bestAggScore = e.aggressiveScore;\n                    bestAgg = room;\n                    bestAggEval = e;\n                }\n            }\n        }\n    }\n\n    for (int H = 4; H <= 10; H++) {\n        for (int W = 4; W <= 10; W++) {\n            for (int corner = 0; corner < 4; corner++) {\n                Room room = make_room(corner, H, W);\n                RoomEval e = evaluate_room(room);\n                if (e.safeScore > bestSafeScore) {\n                    bestSafeScore = e.safeScore;\n                    bestSafe = room;\n                    bestSafeEval = e;\n                }\n            }\n        }\n    }\n\n    bool risky =\n        bestAggEval.insidePets > 0 ||\n        bestAggEval.insideDogs > 0 ||\n        bestAggEval.expandedPets >= 5 ||\n        bestAggEval.nearDoorDogs >= 9 ||\n        bestAggEval.sumBest >= 55 ||\n        bestAggEval.tasks >= 25;\n\n    if (risky) return bestSafe;\n    return bestAgg;\n}\n\nBFSRes bfs_from(pair<int,int> st, const array<array<bool, S>, S>& blocked) {\n    BFSRes res;\n    queue<pair<int,int>> q;\n    auto [sr, sc] = st;\n    res.dist[sr][sc] = 0;\n    res.first[sr][sc] = '.';\n    q.push(st);\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n        for (int k = 0; k < 4; k++) {\n            int nr = r + dr[k], nc = c + dc[k];\n            if (!inb(nr, nc)) continue;\n            if (blocked[nr][nc]) continue;\n            if (res.dist[nr][nc] != -1) continue;\n            res.dist[nr][nc] = res.dist[r][c] + 1;\n            res.first[nr][nc] = (res.dist[r][c] == 0 ? moveChar[k] : res.first[r][c]);\n            q.push({nr, nc});\n        }\n    }\n    return res;\n}\n\nvector<BFSRes> all_bfs(const array<array<bool, S>, S>& blocked) {\n    vector<BFSRes> v(M);\n    for (int i = 0; i < M; i++) v[i] = bfs_from(humansPos[i], blocked);\n    return v;\n}\n\nvoid rebuild_counts(array<array<int, S>, S>& humanCnt,\n                    array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            humanCnt[i][j] = 0;\n            petCnt[i][j] = 0;\n        }\n    }\n    for (auto [r, c] : humansPos) humanCnt[r][c]++;\n    for (auto [r, c] : petsPos) petCnt[r][c]++;\n}\n\nbool can_block_cell(int tr, int tc,\n                    const array<array<int, S>, S>& humanCnt,\n                    const array<array<int, S>, S>& petCnt) {\n    if (!inb(tr, tc)) return false;\n    if (humanCnt[tr][tc] > 0) return false;\n    if (petCnt[tr][tc] > 0) return false;\n    for (int k = 0; k < 4; k++) {\n        int nr = tr + dr[k], nc = tc + dc[k];\n        if (!inb(nr, nc)) continue;\n        if (petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nbool unfinished_exists(const Room& room) {\n    for (auto &t : room.tasks) {\n        if (!wallCell[t.wr][t.wc]) return true;\n    }\n    return false;\n}\n\nint pets_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : petsPos) if (room.inside(r, c)) cnt++;\n    return cnt;\n}\n\nint humans_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : humansPos) if (room.inside(r, c)) cnt++;\n    return cnt;\n}\n\nint required_inside_count(int turn) {\n    int dogCnt = count_dogs();\n    int req = M - (dogCnt > 0 ? 1 : 0);\n    if (turn >= 240) req = min(req, M - 1);\n    if (turn >= 285) req = min(req, M - 2);\n    return max(1, req);\n}\n\nbool should_close_final(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 275 && petsInside <= 1) return true;\n    if (turn >= 292 && petsInside <= 2) return true;\n    if (turn >= 298) return true;\n    return false;\n}\n\npair<int,int> decoy_target(const Room& room) {\n    int tr = (room.r1 == 0 ? 24 : 5);\n    int tc = (room.c1 == 0 ? 24 : 5);\n    return {tr, tc};\n}\n\nint live_door_risk(const Door& d) {\n    int risk = 0;\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        int dist = abs(r - d.wr) + abs(c - d.wc);\n        if (dist == 0) risk += 100000;\n        else if (dist == 1) risk += 50000;\n        else if (dist <= 3) risk += (4 - dist) * 200;\n        if (petsType[i] == 4 && dist <= 6) risk += (7 - dist) * 80;\n    }\n    return risk;\n}\n\nint assign_to_target(const Room& room,\n                     const vector<BFSRes>& bfs,\n                     vector<bool>& used,\n                     string& act,\n                     int tr, int tc,\n                     bool preferInside) {\n    int best = -1, bestD = INF;\n\n    bool hasInsideCandidate = false;\n    if (preferInside) {\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            if (!room.inside(humansPos[i].first, humansPos[i].second)) continue;\n            int d = bfs[i].dist[tr][tc];\n            if (d >= 0) hasInsideCandidate = true;\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (used[i]) continue;\n        if (preferInside && hasInsideCandidate &&\n            !room.inside(humansPos[i].first, humansPos[i].second)) continue;\n        int d = bfs[i].dist[tr][tc];\n        if (d < 0) continue;\n        if (d < bestD) {\n            bestD = d;\n            best = i;\n        }\n    }\n\n    if (best != -1) {\n        used[best] = true;\n        if (bestD > 0) act[best] = bfs[best].first[tr][tc];\n    }\n    return best;\n}\n\nbool try_build_door_now(const Door& door,\n                        const array<array<int, S>, S>& humanCnt,\n                        const array<array<int, S>, S>& petCnt,\n                        vector<bool>& used,\n                        string& act) {\n    if (!can_block_cell(door.wr, door.wc, humanCnt, petCnt)) return false;\n    for (int i = 0; i < M; i++) {\n        if (used[i]) continue;\n        auto [r, c] = humansPos[i];\n        if (r == door.sr && c == door.sc) {\n            act[i] = door.act;\n            used[i] = true;\n            return true;\n        }\n    }\n    return false;\n}\n\nstring plan_build_actions(const Room& room,\n                          const array<array<int, S>, S>& humanCnt,\n                          const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n\n    vector<int> unfinished;\n    for (int i = 0; i < (int)room.tasks.size(); i++) {\n        auto &t = room.tasks[i];\n        if (!wallCell[t.wr][t.wc]) unfinished.push_back(i);\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    vector<bool> humanUsed(M, false);\n    vector<bool> taskUsed(room.tasks.size(), false);\n\n    for (int i = 0; i < M; i++) {\n        auto [hr, hc] = humansPos[i];\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                if (can_block_cell(t.wr, t.wc, humanCnt, petCnt) && !toBlock[t.wr][t.wc]) {\n                    act[i] = t.act;\n                    humanUsed[i] = true;\n                    taskUsed[idx] = true;\n                    toBlock[t.wr][t.wc] = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    array<array<bool, S>, S> blocked = wallCell;\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) blocked[i][j] = true;\n        }\n    }\n\n    vector<BFSRes> bfs = all_bfs(blocked);\n    vector<int> assignedTask(M, -1);\n\n    while (true) {\n        int bestH = -1, bestT = -1, bestD = INF;\n        for (int i = 0; i < M; i++) {\n            if (humanUsed[i]) continue;\n            for (int idx : unfinished) {\n                if (taskUsed[idx]) continue;\n                auto &t = room.tasks[idx];\n                int d = bfs[i].dist[t.sr][t.sc];\n                if (d <= 0) continue;\n                if (d < bestD) {\n                    bestD = d;\n                    bestH = i;\n                    bestT = idx;\n                }\n            }\n        }\n        if (bestH == -1) break;\n        humanUsed[bestH] = true;\n        taskUsed[bestT] = true;\n        assignedTask[bestH] = bestT;\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (assignedTask[i] != -1) {\n            auto &t = room.tasks[assignedTask[i]];\n            char mv = bfs[i].first[t.sr][t.sc];\n            if (mv) act[i] = mv;\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (act[i] != '.') continue;\n        auto [hr, hc] = humansPos[i];\n\n        bool onSomeUnfinishedStance = false;\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                onSomeUnfinishedStance = true;\n                break;\n            }\n        }\n        if (onSomeUnfinishedStance) continue;\n\n        int d = bfs[i].dist[room.centerR][room.centerC];\n        if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n    }\n\n    return act;\n}\n\nstring plan_wait_actions(const Room& room, int turn,\n                         const array<array<int, S>, S>& humanCnt,\n                         const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n    vector<bool> used(M, false);\n\n    array<array<bool, S>, S> blocked = wallCell;\n    vector<BFSRes> bfs = all_bfs(blocked);\n\n    vector<int> openDoors;\n    for (int d = 0; d < 2; d++) {\n        if (!wallCell[room.doors[d].wr][room.doors[d].wc]) openDoors.push_back(d);\n    }\n\n    int insideCnt = humans_inside_count(room);\n    int needInside = required_inside_count(turn);\n    int petsInside = pets_inside_count(room);\n    bool hasDog = (count_dogs() > 0);\n    auto [decoyR, decoyC] = decoy_target(room);\n\n    if ((int)openDoors.size() == 2) {\n        int d0 = openDoors[0], d1 = openDoors[1];\n        int risk0 = live_door_risk(room.doors[d0]);\n        int risk1 = live_door_risk(room.doors[d1]);\n\n        int keepDoor = (risk0 <= risk1 ? d0 : d1);\n        int closeDoor = (keepDoor == d0 ? d1 : d0);\n\n        int chosenClose = -1;\n        if (can_block_cell(room.doors[closeDoor].wr, room.doors[closeDoor].wc, humanCnt, petCnt)) {\n            chosenClose = closeDoor;\n        } else if (turn >= 240 &&\n                   can_block_cell(room.doors[keepDoor].wr, room.doors[keepDoor].wc, humanCnt, petCnt)) {\n            chosenClose = keepDoor;\n        }\n\n        if (chosenClose != -1) {\n            if (!try_build_door_now(room.doors[chosenClose], humanCnt, petCnt, used, act)) {\n                assign_to_target(room, bfs, used, act,\n                                 room.doors[chosenClose].sr, room.doors[chosenClose].sc,\n                                 true);\n            }\n        } else {\n            assign_to_target(room, bfs, used, act,\n                             room.doors[closeDoor].sr, room.doors[closeDoor].sc,\n                             true);\n        }\n\n        int futureMain = (chosenClose == -1 ? keepDoor : (chosenClose == keepDoor ? closeDoor : keepDoor));\n        if (turn >= 180 || insideCnt >= needInside) {\n            assign_to_target(room, bfs, used, act,\n                             room.doors[futureMain].sr, room.doors[futureMain].sc,\n                             true);\n        }\n\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            auto [r, c] = humansPos[i];\n            if (room.inside(r, c)) {\n                int d = bfs[i].dist[room.centerR][room.centerC];\n                if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n            } else {\n                if (insideCnt < needInside) {\n                    int d = bfs[i].dist[room.centerR][room.centerC];\n                    if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                } else if (hasDog) {\n                    int d = bfs[i].dist[decoyR][decoyC];\n                    if (d > 0) act[i] = bfs[i].first[decoyR][decoyC];\n                } else {\n                    int d = bfs[i].dist[room.centerR][room.centerC];\n                    if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                }\n            }\n        }\n        return act;\n    }\n\n    if ((int)openDoors.size() == 1) {\n        int d = openDoors[0];\n        const Door& door = room.doors[d];\n\n        bool closeNow = (insideCnt >= needInside) &&\n                        should_close_final(turn, petsInside) &&\n                        can_block_cell(door.wr, door.wc, humanCnt, petCnt);\n\n        if (closeNow) {\n            if (!try_build_door_now(door, humanCnt, petCnt, used, act)) {\n                assign_to_target(room, bfs, used, act, door.sr, door.sc, true);\n            }\n        } else {\n            if (insideCnt >= needInside || petsInside == 0 || turn >= 220) {\n                assign_to_target(room, bfs, used, act, door.sr, door.sc, true);\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            auto [r, c] = humansPos[i];\n            if (room.inside(r, c)) {\n                int dd = bfs[i].dist[room.centerR][room.centerC];\n                if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n            } else {\n                if (insideCnt < needInside) {\n                    int dd = bfs[i].dist[room.centerR][room.centerC];\n                    if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                } else if (hasDog) {\n                    int dd = bfs[i].dist[decoyR][decoyC];\n                    if (dd > 0) act[i] = bfs[i].first[decoyR][decoyC];\n                } else {\n                    int dd = bfs[i].dist[room.centerR][room.centerC];\n                    if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                }\n            }\n        }\n        return act;\n    }\n\n    return act;\n}\n\nstring sanitize_actions(string act,\n                        const array<array<int, S>, S>& humanCnt,\n                        const array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_lower_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [tr, tc] = apply_dir({r, c}, a);\n        if (!can_block_cell(tr, tc, humanCnt, petCnt)) {\n            act[i] = '.';\n        }\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_lower_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [tr, tc] = apply_dir({r, c}, a);\n        if (inb(tr, tc)) toBlock[tr][tc] = true;\n    }\n\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_upper_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [nr, nc] = apply_dir({r, c}, a);\n        if (!inb(nr, nc) || wallCell[nr][nc] || toBlock[nr][nc]) {\n            act[i] = '.';\n        }\n    }\n\n    return act;\n}\n\nvoid apply_human_actions(const string& act) {\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (is_lower_act(a)) {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc)) toBlock[nr][nc] = true;\n        }\n    }\n\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) wallCell[i][j] = true;\n        }\n    }\n\n    vector<pair<int,int>> newHumans = humansPos;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (is_upper_act(a)) {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc) && !wallCell[nr][nc]) {\n                newHumans[i] = {nr, nc};\n            }\n        }\n    }\n    humansPos.swap(newHumans);\n}\n\nvoid apply_pet_moves(const vector<string>& petMoves) {\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        for (char ch : petMoves[i]) {\n            if (ch == '.') continue;\n            auto [nr, nc] = apply_dir({r, c}, ch);\n            r = nr;\n            c = nc;\n        }\n        petsPos[i] = {r, c};\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    petsPos.resize(N);\n    petsType.resize(N);\n    for (int i = 0; i < N; i++) {\n        int x, y, t;\n        cin >> x >> y >> t;\n        --x; --y;\n        petsPos[i] = {x, y};\n        petsType[i] = t;\n    }\n\n    cin >> M;\n    humansPos.resize(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        --x; --y;\n        humansPos[i] = {x, y};\n    }\n\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) wallCell[i][j] = false;\n\n    Room room = choose_room();\n\n    for (int turn = 0; turn < MAX_TURN; turn++) {\n        array<array<int, S>, S> humanCnt, petCnt;\n        rebuild_counts(humanCnt, petCnt);\n\n        string act(M, '.');\n\n        bool fullyClosed =\n            wallCell[room.doors[0].wr][room.doors[0].wc] &&\n            wallCell[room.doors[1].wr][room.doors[1].wc];\n\n        if (fullyClosed) {\n            act = string(M, '.');\n        } else if (unfinished_exists(room)) {\n            act = plan_build_actions(room, humanCnt, petCnt);\n        } else {\n            act = plan_wait_actions(room, turn, humanCnt, petCnt);\n        }\n\n        act = sanitize_actions(act, humanCnt, petCnt);\n\n        cout << act << '\\n' << flush;\n\n        apply_human_actions(act);\n\n        vector<string> petMoves(N);\n        for (int i = 0; i < N; i++) {\n            if (!(cin >> petMoves[i])) return 0;\n        }\n        apply_pet_moves(petMoves);\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nconstexpr int N = 20;\nconstexpr int V = N * N;\nconstexpr int LMAX = 200;\nconstexpr int NONE = 4;\nconstexpr double EPS = 1e-12;\n\nconst char ACT[4] = {'U', 'D', 'L', 'R'};\nconst int prefDirOrder[4] = {1, 3, 0, 2}; // D, R, U, L\nconst int isUL[4] = {1, 0, 1, 0};\n\nint si, sj, ti, tj, sid, tid;\ndouble p_forget, p_move;\n\nstring H[N];\nstring VW[N - 1];\n\nint toCell[V][4];\nunsigned char transKind[V][4]; // 0: stay, 1: move, 2: hit target\nvector<int> neighbors[V];\n\nint distToT[V];\nbool spValid[V][4];\n\ndouble hitReward[LMAX + 1];\ndouble UB[LMAX + 2][V];\n\ndouble preDist[LMAX + 1][V];\ndouble sufVal[LMAX + 2][V];\ndouble prefScore[LMAX + 1];\ndouble aliveMass[LMAX + 1];\n\nint dpMinTurn[V][5];\nint dpMaxTurn[V][5];\n\ninline int ID(int i, int j) { return i * N + j; }\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\ninline double dot400(const double* a, const double* b) {\n    double s = 0.0;\n    for (int i = 0; i < V; i++) s += a[i] * b[i];\n    return s;\n}\n\ninline double dot400_arr(const array<double, V>& a, const double* b) {\n    double s = 0.0;\n    for (int i = 0; i < V; i++) s += a[i] * b[i];\n    return s;\n}\n\nvoid buildTransitions() {\n    for (int c = 0; c < V; c++) neighbors[c].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = ID(i, j);\n\n            // U\n            if (i > 0 && VW[i - 1][j] == '0') toCell[c][0] = ID(i - 1, j);\n            else toCell[c][0] = c;\n\n            // D\n            if (i < N - 1 && VW[i][j] == '0') toCell[c][1] = ID(i + 1, j);\n            else toCell[c][1] = c;\n\n            // L\n            if (j > 0 && H[i][j - 1] == '0') toCell[c][2] = ID(i, j - 1);\n            else toCell[c][2] = c;\n\n            // R\n            if (j < N - 1 && H[i][j] == '0') toCell[c][3] = ID(i, j + 1);\n            else toCell[c][3] = c;\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            int nc = toCell[c][a];\n            if (nc != c) neighbors[c].push_back(nc);\n        }\n        sort(neighbors[c].begin(), neighbors[c].end());\n        neighbors[c].erase(unique(neighbors[c].begin(), neighbors[c].end()), neighbors[c].end());\n    }\n\n    // Target absorbing for value DP\n    for (int a = 0; a < 4; a++) toCell[tid][a] = tid;\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c == tid) transKind[c][a] = 0;\n            else if (toCell[c][a] == c) transKind[c][a] = 0;\n            else if (toCell[c][a] == tid) transKind[c][a] = 2;\n            else transKind[c][a] = 1;\n        }\n    }\n}\n\nvoid bfsDistToTarget() {\n    fill(distToT, distToT + V, -1);\n    queue<int> q;\n    distToT[tid] = 0;\n    q.push(tid);\n\n    while (!q.empty()) {\n        int c = q.front();\n        q.pop();\n        for (int nc : neighbors[c]) {\n            if (distToT[nc] == -1) {\n                distToT[nc] = distToT[c] + 1;\n                q.push(nc);\n            }\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c != tid && transKind[c][a] != 0) {\n                int nc = toCell[c][a];\n                spValid[c][a] = (distToT[nc] == distToT[c] - 1);\n            } else {\n                spValid[c][a] = false;\n            }\n        }\n    }\n}\n\nvoid computeAdaptiveUpperBound() {\n    for (int c = 0; c < V; c++) UB[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        UB[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                double val;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val = UB[t + 1][c];\n                } else if (k == 2) {\n                    val = hitReward[t] + p_forget * UB[t + 1][c];\n                } else {\n                    int nc = toCell[c][a];\n                    val = p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc];\n                }\n                if (val > best) best = val;\n            }\n            UB[t][c] = best;\n        }\n    }\n}\n\nvector<int> rolloutFrom(const double* startDist, int prefixLen, bool stochastic, double temp, XorShift64& rng) {\n    int rem = LMAX - prefixLen;\n    vector<int> seq(rem, 0);\n    array<double, V> dist{};\n    for (int c = 0; c < V; c++) dist[c] = startDist[c];\n\n    for (int step = 0; step < rem; step++) {\n        int turn = prefixLen + step + 1; // 1-based\n        double val[4];\n        for (int a = 0; a < 4; a++) {\n            double cur = 0.0;\n            for (int c = 0; c < V; c++) {\n                double q = dist[c];\n                if (q < 1e-18) continue;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    cur += q * UB[turn + 1][c];\n                } else if (k == 2) {\n                    cur += q * (hitReward[turn] + p_forget * UB[turn + 1][c]);\n                } else {\n                    int nc = toCell[c][a];\n                    cur += q * (p_forget * UB[turn + 1][c] + p_move * UB[turn + 1][nc]);\n                }\n            }\n            val[a] = cur;\n        }\n\n        int chosen = 0;\n        if (!stochastic) {\n            double bestVal = -1e100;\n            for (int kk = 0; kk < 4; kk++) {\n                int a = prefDirOrder[kk];\n                if (val[a] > bestVal + 1e-15) {\n                    bestVal = val[a];\n                    chosen = a;\n                }\n            }\n        } else {\n            double mx = max(max(val[0], val[1]), max(val[2], val[3]));\n            double w[4], sum = 0.0;\n            for (int a = 0; a < 4; a++) {\n                double z = (val[a] - mx) / temp;\n                w[a] = (z < -50.0 ? 0.0 : exp(z));\n                sum += w[a];\n            }\n            if (sum <= 0.0) {\n                chosen = prefDirOrder[rng.nextInt(4)];\n            } else {\n                double r = rng.nextDouble() * sum;\n                double acc = 0.0;\n                for (int kk = 0; kk < 4; kk++) {\n                    int a = prefDirOrder[kk];\n                    acc += w[a];\n                    if (r <= acc) {\n                        chosen = a;\n                        break;\n                    }\n                }\n            }\n        }\n\n        seq[step] = chosen;\n\n        array<double, V> nd{};\n        nd.fill(0.0);\n        for (int c = 0; c < V; c++) {\n            double q = dist[c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][chosen];\n            if (k == 0) {\n                nd[c] += q;\n            } else if (k == 2) {\n                nd[c] += q * p_forget;\n            } else {\n                int nc = toCell[c][chosen];\n                nd[c] += q * p_forget;\n                nd[nc] += q * p_move;\n            }\n        }\n        dist = nd;\n    }\n\n    return seq;\n}\n\nvector<int> greedyLikeRollout(bool stochastic, double temp, XorShift64& rng) {\n    static double start[V];\n    fill(start, start + V, 0.0);\n    start[sid] = 1.0;\n    return rolloutFrom(start, 0, stochastic, temp, rng);\n}\n\nstruct CurState {\n    array<double, V> dist;\n    double score;\n};\n\nstruct CandState {\n    array<double, V> dist;\n    double score;\n    double pri;\n    int parent;\n    unsigned char act;\n};\n\nstruct ParentInfo {\n    int parent;\n    unsigned char act;\n};\n\nvector<vector<int>> beamSearchFrom(const double* startDist, int prefixLen, int beamWidth, int topM) {\n    int rem = LMAX - prefixLen;\n    vector<vector<ParentInfo>> parent(rem + 1);\n\n    vector<CurState> cur, nxt;\n    cur.reserve(beamWidth);\n    nxt.reserve(beamWidth);\n\n    CurState root;\n    root.dist.fill(0.0);\n    for (int c = 0; c < V; c++) root.dist[c] = startDist[c];\n    root.score = 0.0;\n    cur.push_back(root);\n\n    vector<CandState> cand;\n    cand.reserve(beamWidth * 4);\n    vector<int> ord;\n\n    for (int d = 0; d < rem; d++) {\n        int turn = prefixLen + d + 1;\n        cand.clear();\n\n        for (int idx = 0; idx < (int)cur.size(); idx++) {\n            const auto& st = cur[idx];\n            for (int a = 0; a < 4; a++) {\n                CandState cs;\n                cs.dist.fill(0.0);\n                cs.parent = idx;\n                cs.act = (unsigned char)a;\n                double scoreAfter = st.score;\n                double pri = st.score;\n\n                for (int c = 0; c < V; c++) {\n                    double q = st.dist[c];\n                    if (q < 1e-18) continue;\n                    unsigned char k = transKind[c][a];\n                    if (k == 0) {\n                        cs.dist[c] += q;\n                        pri += q * UB[turn + 1][c];\n                    } else if (k == 2) {\n                        cs.dist[c] += q * p_forget;\n                        scoreAfter += q * hitReward[turn];\n                        pri += q * (hitReward[turn] + p_forget * UB[turn + 1][c]);\n                    } else {\n                        int nc = toCell[c][a];\n                        cs.dist[c] += q * p_forget;\n                        cs.dist[nc] += q * p_move;\n                        pri += q * (p_forget * UB[turn + 1][c] + p_move * UB[turn + 1][nc]);\n                    }\n                }\n\n                cs.score = scoreAfter;\n                cs.pri = pri;\n                cand.push_back(std::move(cs));\n            }\n        }\n\n        int k = min(beamWidth, (int)cand.size());\n        ord.resize(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n\n        auto cmp = [&](int x, int y) {\n            if (cand[x].pri != cand[y].pri) return cand[x].pri > cand[y].pri;\n            if (cand[x].score != cand[y].score) return cand[x].score > cand[y].score;\n            if (cand[x].parent != cand[y].parent) return cand[x].parent < cand[y].parent;\n            return cand[x].act < cand[y].act;\n        };\n        partial_sort(ord.begin(), ord.begin() + k, ord.end(), cmp);\n\n        nxt.clear();\n        parent[d + 1].resize(k);\n        for (int i = 0; i < k; i++) {\n            int id = ord[i];\n            CurState ns;\n            ns.dist = cand[id].dist;\n            ns.score = cand[id].score;\n            nxt.push_back(std::move(ns));\n            parent[d + 1][i] = ParentInfo{cand[id].parent, cand[id].act};\n        }\n        cur.swap(nxt);\n    }\n\n    vector<int> finalOrd(cur.size());\n    iota(finalOrd.begin(), finalOrd.end(), 0);\n    sort(finalOrd.begin(), finalOrd.end(), [&](int x, int y) {\n        if (cur[x].score != cur[y].score) return cur[x].score > cur[y].score;\n        return x < y;\n    });\n\n    topM = min(topM, (int)finalOrd.size());\n    vector<vector<int>> res;\n    for (int z = 0; z < topM; z++) {\n        int idx = finalOrd[z];\n        vector<int> suf(rem);\n        for (int d = rem; d >= 1; d--) {\n            suf[d - 1] = parent[d][idx].act;\n            idx = parent[d][idx].parent;\n        }\n        res.push_back(std::move(suf));\n    }\n    return res;\n}\n\nvector<vector<int>> beamSearch(int beamWidth, int topM) {\n    static double start[V];\n    fill(start, start + V, 0.0);\n    start[sid] = 1.0;\n    return beamSearchFrom(start, 0, beamWidth, topM);\n}\n\nvector<int> buildShortestPathByTurns(bool maximizeTurns) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return distToT[a] < distToT[b];\n    });\n\n    const int INF = 1e9;\n\n    for (int c : ids) {\n        for (int last = 0; last < 5; last++) {\n            if (c == tid) {\n                dpMinTurn[c][last] = 0;\n                dpMaxTurn[c][last] = 0;\n                continue;\n            }\n\n            int bestMin = INF;\n            int bestMax = -INF;\n\n            for (int a = 0; a < 4; a++) {\n                if (!spValid[c][a]) continue;\n                int nc = toCell[c][a];\n                int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n                bestMin = min(bestMin, turnCost + isUL[a] + dpMinTurn[nc][a]);\n                bestMax = max(bestMax, turnCost - isUL[a] + dpMaxTurn[nc][a]);\n            }\n\n            dpMinTurn[c][last] = bestMin;\n            dpMaxTurn[c][last] = bestMax;\n        }\n    }\n\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n\n    while (c != tid) {\n        int bestA = -1;\n        int bestVal = maximizeTurns ? -INF : INF;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n            int val;\n            if (maximizeTurns) {\n                val = turnCost - isUL[a] + dpMaxTurn[nc][a];\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            } else {\n                val = turnCost + isUL[a] + dpMinTurn[nc][a];\n                if (val < bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            }\n        }\n\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n\n    return path;\n}\n\nvector<int> repeatPathTo200(const vector<int>& path) {\n    vector<int> seq(LMAX, 1);\n    if (path.empty()) return seq;\n    for (int t = 0; t < LMAX; t++) seq[t] = path[t % (int)path.size()];\n    return seq;\n}\n\nvector<int> inflateAndRepeat(const vector<int>& path, int rep) {\n    vector<int> ext;\n    if (path.empty()) return vector<int>(LMAX, 1);\n    ext.reserve((int)path.size() * rep);\n    for (int a : path) for (int r = 0; r < rep; r++) ext.push_back(a);\n    return repeatPathTo200(ext);\n}\n\nvector<int> makePeriodic(const vector<int>& pat) {\n    vector<int> seq(LMAX);\n    for (int t = 0; t < LMAX; t++) seq[t] = pat[t % (int)pat.size()];\n    return seq;\n}\n\nvector<int> randomWeightedShortestPath(XorShift64& rng, double wTurn, double wBlock, double noise) {\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n    while (c != tid) {\n        int bestA = -1;\n        double bestS = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            double s = 0.0;\n            if (last != NONE && last != a) s += wTurn;\n            if (nc == tid || toCell[nc][a] == nc) s += wBlock;\n            s += noise * rng.nextDouble();\n            if (s > bestS) {\n                bestS = s;\n                bestA = a;\n            }\n        }\n\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n    return path;\n}\n\nvoid computeForward(const vector<int>& seq) {\n    fill(preDist[0], preDist[0] + V, 0.0);\n    preDist[0][sid] = 1.0;\n    prefScore[0] = 0.0;\n    aliveMass[0] = 1.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        fill(preDist[t], preDist[t] + V, 0.0);\n        int a = seq[t - 1];\n        double sc = prefScore[t - 1];\n\n        for (int c = 0; c < V; c++) {\n            double q = preDist[t - 1][c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                preDist[t][c] += q;\n            } else if (k == 2) {\n                preDist[t][c] += q * p_forget;\n                sc += q * hitReward[t];\n            } else {\n                int nc = toCell[c][a];\n                preDist[t][c] += q * p_forget;\n                preDist[t][nc] += q * p_move;\n            }\n        }\n\n        prefScore[t] = sc;\n        double alive = 0.0;\n        for (int c = 0; c < V; c++) alive += preDist[t][c];\n        aliveMass[t] = alive;\n    }\n}\n\nvoid computeBackward(const vector<int>& seq) {\n    for (int c = 0; c < V; c++) sufVal[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        int a = seq[t - 1];\n        sufVal[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                sufVal[t][c] = sufVal[t + 1][c];\n            } else if (k == 2) {\n                sufVal[t][c] = hitReward[t] + p_forget * sufVal[t + 1][c];\n            } else {\n                int nc = toCell[c][a];\n                sufVal[t][c] = p_forget * sufVal[t + 1][c] + p_move * sufVal[t + 1][nc];\n            }\n        }\n    }\n}\n\ndouble exactScore(const vector<int>& seq) {\n    computeForward(seq);\n    return prefScore[LMAX];\n}\n\ninline void applyActionValue(int pos, int a, const double* next, double* out) {\n    out[tid] = 0.0;\n    for (int c = 0; c < V; c++) {\n        if (c == tid) continue;\n        unsigned char k = transKind[c][a];\n        if (k == 0) {\n            out[c] = next[c];\n        } else if (k == 2) {\n            out[c] = hitReward[pos] + p_forget * next[c];\n        } else {\n            int nc = toCell[c][a];\n            out[c] = p_forget * next[c] + p_move * next[nc];\n        }\n    }\n}\n\nstruct Change {\n    int k = 0;\n    int pos = -1;\n    int a[4] = {0, 0, 0, 0};\n    double score = -1e100;\n};\n\nChange searchBest1(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double out[V];\n\n    for (int t = 1; t <= LMAX; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n        const double* nxt = sufVal[t + 1];\n\n        for (int a = 0; a < 4; a++) {\n            if (a == seq[t - 1]) continue;\n            applyActionValue(t, a, nxt, out);\n            double val = base + dot400(pre, out);\n            if (val > best.score + EPS) {\n                best.score = val;\n                best.k = 1;\n                best.pos = t - 1;\n                best.a[0] = a;\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest2(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double mid[4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 1; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        for (int b = 0; b < 4; b++) applyActionValue(t + 1, b, sufVal[t + 2], mid[b]);\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                if (a == seq[t - 1] && b == seq[t]) continue;\n                applyActionValue(t, a, mid[b], out);\n                double val = base + dot400(pre, out);\n                if (val > best.score + EPS) {\n                    best.score = val;\n                    best.k = 2;\n                    best.pos = t - 1;\n                    best.a[0] = a;\n                    best.a[1] = b;\n                }\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest3(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double tail[4][V];\n    static double mid[4][4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 2; t++) {\n        if ((t & 7) == 0 && Clock::now() >= deadline) break;\n\n        for (int c = 0; c < 4; c++) applyActionValue(t + 2, c, sufVal[t + 3], tail[c]);\n        for (int b = 0; b < 4; b++) {\n            for (int c = 0; c < 4; c++) {\n                applyActionValue(t + 1, b, tail[c], mid[b][c]);\n            }\n        }\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                for (int c = 0; c < 4; c++) {\n                    if (a == seq[t - 1] && b == seq[t] && c == seq[t + 1]) continue;\n                    applyActionValue(t, a, mid[b][c], out);\n                    double val = base + dot400(pre, out);\n                    if (val > best.score + EPS) {\n                        best.score = val;\n                        best.k = 3;\n                        best.pos = t - 1;\n                        best.a[0] = a;\n                        best.a[1] = b;\n                        best.a[2] = c;\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\ndouble localDescent(vector<int>& seq, const Clock::time_point& deadline, int maxIter, bool allow3) {\n    computeForward(seq);\n    double curScore = prefScore[LMAX];\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (Clock::now() >= deadline) break;\n        computeBackward(seq);\n\n        Change best = searchBest1(seq, curScore, deadline);\n        if (Clock::now() >= deadline) break;\n\n        Change c2 = searchBest2(seq, curScore, deadline);\n        if (c2.score > best.score + EPS) best = c2;\n\n        if (allow3 && best.k == 0 && iter < 5) {\n            if (Clock::now() + chrono::milliseconds(40) < deadline) {\n                Change c3 = searchBest3(seq, curScore, deadline);\n                if (c3.score > best.score + EPS) best = c3;\n            }\n        }\n\n        if (best.k == 0) break;\n\n        for (int i = 0; i < best.k; i++) seq[best.pos + i] = best.a[i];\n        computeForward(seq);\n        curScore = prefScore[LMAX];\n    }\n\n    return curScore;\n}\n\nstruct WindowChange {\n    int pos = -1;\n    double score = -1e100;\n    int a[4] = {0, 0, 0, 0};\n};\n\nWindowChange searchBestWindow4Exact(const vector<int>& seq, double curScore, int topPos, const Clock::time_point& deadline) {\n    WindowChange best;\n    best.score = curScore;\n\n    vector<pair<double, int>> posCand;\n    posCand.reserve(LMAX);\n\n    for (int s = 0; s + 4 <= LMAX; s++) {\n        if (aliveMass[s] < 1e-9) continue;\n        double gap = 0.0;\n        for (int c = 0; c < V; c++) {\n            double q = preDist[s][c];\n            if (q < 1e-18) continue;\n            gap += q * (UB[s + 1][c] - sufVal[s + 1][c]);\n        }\n        if (gap > 1e-9) posCand.push_back({gap, s});\n    }\n\n    sort(posCand.begin(), posCand.end(), [&](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n    if ((int)posCand.size() > topPos) posCand.resize(topPos);\n\n    static double lv1[4][V];\n    static double lv2[4][4][V];\n    static double lv3[4][4][4][V];\n    static double out[V];\n\n    for (int idx = 0; idx < (int)posCand.size(); idx++) {\n        if ((idx & 3) == 0 && Clock::now() >= deadline) break;\n\n        int s = posCand[idx].second;\n        const double* pre = preDist[s];\n        double base = prefScore[s];\n\n        for (int d = 0; d < 4; d++) applyActionValue(s + 4, d, sufVal[s + 5], lv1[d]);\n        for (int c = 0; c < 4; c++) {\n            for (int d = 0; d < 4; d++) {\n                applyActionValue(s + 3, c, lv1[d], lv2[c][d]);\n            }\n        }\n        for (int b = 0; b < 4; b++) {\n            for (int c = 0; c < 4; c++) {\n                for (int d = 0; d < 4; d++) {\n                    applyActionValue(s + 2, b, lv2[c][d], lv3[b][c][d]);\n                }\n            }\n        }\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                for (int c = 0; c < 4; c++) {\n                    for (int d = 0; d < 4; d++) {\n                        if (a == seq[s] && b == seq[s + 1] && c == seq[s + 2] && d == seq[s + 3]) continue;\n                        applyActionValue(s + 1, a, lv3[b][c][d], out);\n                        double val = base + dot400(pre, out);\n                        if (val > best.score + EPS) {\n                            best.score = val;\n                            best.pos = s;\n                            best.a[0] = a;\n                            best.a[1] = b;\n                            best.a[2] = c;\n                            best.a[3] = d;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nstruct CutInfo {\n    int s;\n    array<double, V> dist;\n};\n\nvector<CutInfo> selectPromisingCuts(int need) {\n    vector<pair<double, int>> cand;\n    cand.reserve(LMAX);\n\n    for (int s = 8; s <= LMAX - 12; s++) {\n        if (aliveMass[s] < 1e-6) continue;\n        double gap = 0.0;\n        for (int c = 0; c < V; c++) {\n            double q = preDist[s][c];\n            if (q < 1e-18) continue;\n            gap += q * (UB[s + 1][c] - sufVal[s + 1][c]);\n        }\n        if (gap <= 1e-10) continue;\n        double score = gap * (0.35 + 0.65 * (double)s / LMAX);\n        cand.push_back({score, s});\n    }\n\n    sort(cand.begin(), cand.end(), [&](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n\n    vector<CutInfo> res;\n    for (auto [score, s] : cand) {\n        bool ok = true;\n        for (auto& ci : res) {\n            if (abs(ci.s - s) < 12) {\n                ok = false;\n                break;\n            }\n        }\n        if (!ok) continue;\n        CutInfo ci;\n        ci.s = s;\n        for (int c = 0; c < V; c++) ci.dist[c] = preDist[s][c];\n        res.push_back(ci);\n        if ((int)res.size() >= need) break;\n    }\n    return res;\n}\n\ndouble trySuffixReplan(vector<int>& seq, double curScore, const Clock::time_point& deadline, bool heavy, XorShift64& rng) {\n    computeForward(seq);\n    computeBackward(seq);\n\n    auto cuts = selectPromisingCuts(heavy ? 3 : 1);\n    if (cuts.empty()) return curScore;\n\n    vector<int> bestSeq = seq;\n    double bestScore = curScore;\n\n    for (int idx = 0; idx < (int)cuts.size(); idx++) {\n        if (Clock::now() + chrono::milliseconds(25) >= deadline) break;\n\n        int s = cuts[idx].s;\n        const double* dist = cuts[idx].dist.data();\n\n        // Deterministic suffix rollout\n        {\n            vector<int> cand = seq;\n            auto suf = rolloutFrom(dist, s, false, 1.0, rng);\n            for (int i = 0; i < (int)suf.size(); i++) cand[s + i] = suf[i];\n            double sc = exactScore(cand);\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = std::move(cand);\n            }\n        }\n\n        // One stochastic suffix rollout\n        if ((heavy || idx == 0) && Clock::now() + chrono::milliseconds(20) < deadline) {\n            vector<int> cand = seq;\n            auto suf = rolloutFrom(dist, s, true, heavy ? 4.0 : 6.0, rng);\n            for (int i = 0; i < (int)suf.size(); i++) cand[s + i] = suf[i];\n            double sc = exactScore(cand);\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = std::move(cand);\n            }\n        }\n\n        // Small beam suffix\n        if ((heavy || idx == 0) && Clock::now() + chrono::milliseconds(30) < deadline) {\n            auto beams = beamSearchFrom(dist, s, heavy ? 28 : 18, 1);\n            for (auto& suf : beams) {\n                vector<int> cand = seq;\n                for (int i = 0; i < (int)suf.size(); i++) cand[s + i] = suf[i];\n                double sc = exactScore(cand);\n                if (sc > bestScore + EPS) {\n                    bestScore = sc;\n                    bestSeq = std::move(cand);\n                }\n            }\n        }\n    }\n\n    if (bestScore > curScore + EPS) {\n        seq = std::move(bestSeq);\n        curScore = localDescent(seq, deadline, heavy ? 6 : 3, false);\n    }\n    return curScore;\n}\n\ndouble improveSequence(vector<int>& seq, const Clock::time_point& deadline, bool heavy, XorShift64& rng) {\n    double sc = localDescent(seq, deadline, heavy ? 18 : 8, heavy);\n\n    // Small exact 4-window\n    if (Clock::now() + chrono::milliseconds(35) < deadline) {\n        computeForward(seq);\n        computeBackward(seq);\n        WindowChange wc = searchBestWindow4Exact(seq, sc, heavy ? 8 : 4, deadline);\n        if (wc.pos != -1 && wc.score > sc + EPS) {\n            for (int i = 0; i < 4; i++) seq[wc.pos + i] = wc.a[i];\n            sc = localDescent(seq, deadline, heavy ? 6 : 3, false);\n        }\n    }\n\n    // Suffix replanning from promising cut points\n    if (Clock::now() + chrono::milliseconds(40) < deadline) {\n        sc = trySuffixReplan(seq, sc, deadline, heavy, rng);\n    }\n\n    return sc;\n}\n\nstring seqToString(const vector<int>& seq) {\n    string s;\n    s.reserve(seq.size());\n    for (int a : seq) s.push_back(ACT[a]);\n    return s;\n}\n\nvoid perturb(vector<int>& seq, const vector<vector<int>>& pool, XorShift64& rng) {\n    int mode = rng.nextInt(4);\n\n    if (mode == 0) {\n        int len = 1 + rng.nextInt(8);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[pos + i] = rng.nextInt(4);\n    } else if (mode == 1 && !pool.empty()) {\n        int len = 5 + rng.nextInt(26);\n        len = min(len, LMAX);\n        int dst = rng.nextInt(LMAX - len + 1);\n        const auto& src = pool[rng.nextInt((int)pool.size())];\n        int srcPos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[dst + i] = src[srcPos + i];\n    } else if (mode == 2) {\n        int cnt = 2 + rng.nextInt(5);\n        for (int k = 0; k < cnt; k++) {\n            int pos = rng.nextInt(LMAX);\n            seq[pos] = rng.nextInt(4);\n        }\n    } else {\n        int len = 3 + rng.nextInt(12);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) {\n            if (rng.nextInt(3) == 0) seq[pos + i] = rng.nextInt(4);\n        }\n    }\n}\n\nuint64_t makeSeed() {\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(si); mix(sj); mix(ti); mix(tj);\n    mix((uint64_t)llround(p_forget * 1000.0));\n    for (int i = 0; i < N; i++) for (char ch : H[i]) mix((uint64_t)ch);\n    for (int i = 0; i < N - 1; i++) for (char ch : VW[i]) mix((uint64_t)ch);\n    return seed;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto globalStart = Clock::now();\n    auto deadline = globalStart + chrono::milliseconds(1930);\n\n    cin >> si >> sj >> ti >> tj >> p_forget;\n    for (int i = 0; i < N; i++) cin >> H[i];\n    for (int i = 0; i < N - 1; i++) cin >> VW[i];\n\n    sid = ID(si, sj);\n    tid = ID(ti, tj);\n    p_move = 1.0 - p_forget;\n\n    for (int t = 1; t <= LMAX; t++) hitReward[t] = p_move * (401 - t);\n\n    buildTransitions();\n    bfsDistToTarget();\n    computeAdaptiveUpperBound();\n\n    XorShift64 rng(makeSeed());\n\n    vector<vector<int>> candidates;\n    candidates.reserve(48);\n\n    // Rollout seeds\n    candidates.push_back(greedyLikeRollout(false, 1.0, rng));\n    candidates.push_back(greedyLikeRollout(true, 2.5, rng));\n    candidates.push_back(greedyLikeRollout(true, 5.0, rng));\n    candidates.push_back(greedyLikeRollout(true, 10.0, rng));\n\n    // Beam seeds\n    {\n        auto beams = beamSearch(84, 3);\n        for (auto& s : beams) candidates.push_back(s);\n    }\n\n    // Shortest-path style seeds\n    auto minTurnPath = buildShortestPathByTurns(false);\n    auto maxTurnPath = buildShortestPathByTurns(true);\n    candidates.push_back(repeatPathTo200(minTurnPath));\n    candidates.push_back(repeatPathTo200(maxTurnPath));\n    candidates.push_back(inflateAndRepeat(minTurnPath, 2));\n    candidates.push_back(inflateAndRepeat(maxTurnPath, 2));\n\n    // Randomized shortest-path variants\n    {\n        vector<tuple<double, double, double>> params = {\n            {-3.0, 0.0, 0.8},\n            { 3.0, 0.0, 0.8},\n            {-1.0, 2.0, 0.8},\n            { 1.0, 2.0, 0.8},\n            { 0.0, 3.0, 0.8},\n            {-2.0, 1.0, 1.5},\n            { 2.0, 1.0, 1.5},\n            { 0.0, 0.0, 2.0}\n        };\n        for (auto [wt, wb, nz] : params) {\n            auto pth = randomWeightedShortestPath(rng, wt, wb, nz);\n            candidates.push_back(repeatPathTo200(pth));\n        }\n    }\n\n    // Periodic robust baselines\n    candidates.push_back(makePeriodic({1, 3}));         // DRDR...\n    candidates.push_back(makePeriodic({3, 1}));         // RDRD...\n    candidates.push_back(makePeriodic({1, 1, 3, 3}));   // DDRR...\n    candidates.push_back(makePeriodic({3, 3, 1, 1}));   // RRDD...\n    candidates.push_back(makePeriodic({1, 3, 1, 3, 1}));\n\n    // Dedup\n    unordered_set<string> seen;\n    vector<vector<int>> uniq;\n    uniq.reserve(candidates.size());\n    for (auto& seq : candidates) {\n        string key = seqToString(seq);\n        if (seen.insert(key).second) uniq.push_back(seq);\n    }\n\n    // Initial exact ranking\n    vector<pair<double, int>> order;\n    order.reserve(uniq.size());\n    for (int i = 0; i < (int)uniq.size(); i++) {\n        double sc = exactScore(uniq[i]);\n        order.push_back({sc, i});\n    }\n    sort(order.begin(), order.end(), greater<pair<double, int>>());\n\n    vector<int> bestSeq = uniq[order[0].second];\n    double bestScore = order[0].first;\n\n    vector<vector<int>> pool;\n    for (int z = 0; z < (int)order.size() && z < 10; z++) {\n        pool.push_back(uniq[order[z].second]);\n    }\n\n    // Improve top seeds\n    int topTrials = min(5, (int)order.size());\n    for (int z = 0; z < topTrials; z++) {\n        if (Clock::now() >= deadline) break;\n        vector<int> seq = uniq[order[z].second];\n        double sc = improveSequence(seq, deadline, z < 2, rng);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n        if ((int)pool.size() < 18) pool.push_back(seq);\n    }\n\n    // Extra polish on current best\n    if (Clock::now() + chrono::milliseconds(80) < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = improveSequence(seq, deadline, true, rng);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    // Perturb + restart\n    while (Clock::now() + chrono::milliseconds(70) < deadline) {\n        vector<int> seq;\n        if (!pool.empty() && rng.nextInt(100) < 35) {\n            seq = pool[rng.nextInt(min<int>((int)pool.size(), 8))];\n        } else {\n            seq = bestSeq;\n        }\n\n        perturb(seq, pool, rng);\n        double sc = improveSequence(seq, deadline, false, rng);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n            if ((int)pool.size() < 20) pool.push_back(seq);\n        } else if ((int)pool.size() < 20 && sc + 0.02 >= bestScore) {\n            pool.push_back(seq);\n        }\n    }\n\n    // Final polish\n    if (Clock::now() < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = improveSequence(seq, deadline, true, rng);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    cout << seqToString(bestSeq) << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int P = N * N;\nstatic constexpr int V = P * 4;\n\nstatic constexpr int DIR_L = 0;\nstatic constexpr int DIR_U = 1;\nstatic constexpr int DIR_R = 2;\nstatic constexpr int DIR_D = 3;\n\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int MATCH_REWARD = 2;\nstatic constexpr int BROKEN_PENALTY = -3;\nstatic constexpr int BOUNDARY_PENALTY = -3;\n\nstatic constexpr long long SCORE_FACTOR = 10000000000LL;\nstatic constexpr long long L2_FACTOR = 1000000LL;\nstatic constexpr long long L1_FACTOR = 100LL;\n\nusing StateArray = array<uint8_t, P>;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 1) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct CycleEval {\n    int L1 = 0;\n    int L2 = 0;\n    int total = 0;\n    int numCycles = 0;\n    long long score = 0;\n    long long scalarNoG = LLONG_MIN / 4;\n};\n\nstruct Eval {\n    int g = 0;\n    CycleEval c;\n    long long scalar = LLONG_MIN / 4;\n};\n\nstruct Candidate {\n    StateArray st{};\n    Eval ev;\n};\n\nstatic const int TO[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\nstatic chrono::steady_clock::time_point g_start;\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ntemplate <class T>\nvoid shuffle_vec(vector<T>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.next_int(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nuint8_t activeMask[8];\nuint8_t stateToRot[8][8];\nuint8_t allowedState[P][4];\nuint8_t allowedCnt[P];\nuint8_t baseTile[P];\nbool isDoublePos[P];\nint16_t neighborPos[P][4];\n\nvector<int> allPos;\nvector<int> nonDoublePos;\nvector<int> doublePos;\nvector<array<int, 4>> blocks2x2;\nvector<array<int, 6>> windows23;\n\nint seenStampCell[P];\nint curStampCell = 1;\nint seenStampBlock[(N - 1) * (N - 1)];\nint curStampBlock = 1;\n\ninline long long make_scalar(const CycleEval& c, int g) {\n    return c.score * SCORE_FACTOR\n         + 1LL * c.L2 * L2_FACTOR\n         + 1LL * c.L1 * L1_FACTOR\n         + 2LL * c.total\n         + g;\n}\n\ninline Eval make_eval(int g, const CycleEval& c) {\n    Eval e;\n    e.g = g;\n    e.c = c;\n    e.scalar = make_scalar(c, g);\n    return e;\n}\n\ninline int rotate_state(int b, int r) {\n    if (b <= 3) return (b + r) & 3;\n    if (b <= 5) return 4 + ((b - 4 + r) & 1);\n    return 6 + ((b - 6 + r) & 1);\n}\n\nvoid init_tables() {\n    for (int s = 0; s < 8; s++) {\n        uint8_t mask = 0;\n        for (int d = 0; d < 4; d++) {\n            if (TO[s][d] != -1) mask |= uint8_t(1u << d);\n        }\n        activeMask[s] = mask;\n    }\n\n    for (int b = 0; b < 8; b++) {\n        for (int s = 0; s < 8; s++) stateToRot[b][s] = 255;\n        for (int r = 0; r < 4; r++) {\n            int s = rotate_state(b, r);\n            stateToRot[b][s] = min<int>(stateToRot[b][s], r);\n        }\n    }\n\n    allPos.reserve(P);\n    nonDoublePos.reserve(P);\n    doublePos.reserve(P);\n    blocks2x2.reserve((N - 1) * (N - 1));\n    windows23.reserve((N - 1) * (N - 2) * 2);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            neighborPos[p][DIR_L] = (j > 0 ? p - 1 : -1);\n            neighborPos[p][DIR_U] = (i > 0 ? p - N : -1);\n            neighborPos[p][DIR_R] = (j + 1 < N ? p + 1 : -1);\n            neighborPos[p][DIR_D] = (i + 1 < N ? p + N : -1);\n        }\n    }\n\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j + 1 < N; j++) {\n            blocks2x2.push_back({i * N + j, i * N + (j + 1), (i + 1) * N + j, (i + 1) * N + (j + 1)});\n        }\n    }\n\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j + 2 < N; j++) {\n            windows23.push_back({\n                i * N + j, i * N + (j + 1), i * N + (j + 2),\n                (i + 1) * N + j, (i + 1) * N + (j + 1), (i + 1) * N + (j + 2)\n            });\n        }\n    }\n    for (int i = 0; i + 2 < N; i++) {\n        for (int j = 0; j + 1 < N; j++) {\n            windows23.push_back({\n                i * N + j, i * N + (j + 1),\n                (i + 1) * N + j, (i + 1) * N + (j + 1),\n                (i + 2) * N + j, (i + 2) * N + (j + 1)\n            });\n        }\n    }\n}\n\ninline uint8_t get_state_override(const StateArray& st, int pos, int overridePos, uint8_t overrideState) {\n    return (pos == overridePos ? overrideState : st[pos]);\n}\n\ninline int ownerContrib(int pos, const StateArray& st, int overridePos = -1, uint8_t overrideState = 0) {\n    int i = pos / N, j = pos % N;\n    uint8_t s = get_state_override(st, pos, overridePos, overrideState);\n    uint8_t m = activeMask[s];\n    int g = 0;\n\n    if (j == 0 && (m & (1u << DIR_L))) g += BOUNDARY_PENALTY;\n    if (i == 0 && (m & (1u << DIR_U))) g += BOUNDARY_PENALTY;\n\n    if (j + 1 < N) {\n        bool a = (m >> DIR_R) & 1u;\n        bool b = (activeMask[get_state_override(st, pos + 1, overridePos, overrideState)] >> DIR_L) & 1u;\n        if (a && b) g += MATCH_REWARD;\n        else if (a != b) g += BROKEN_PENALTY;\n    } else {\n        if (m & (1u << DIR_R)) g += BOUNDARY_PENALTY;\n    }\n\n    if (i + 1 < N) {\n        bool a = (m >> DIR_D) & 1u;\n        bool b = (activeMask[get_state_override(st, pos + N, overridePos, overrideState)] >> DIR_U) & 1u;\n        if (a && b) g += MATCH_REWARD;\n        else if (a != b) g += BROKEN_PENALTY;\n    } else {\n        if (m & (1u << DIR_D)) g += BOUNDARY_PENALTY;\n    }\n\n    return g;\n}\n\ninline int localCellScore(int pos, uint8_t s, const StateArray& st) {\n    int sc = 0;\n    uint8_t mask = activeMask[s];\n    for (int d = 0; d < 4; d++) {\n        bool a = (mask >> d) & 1u;\n        int np = neighborPos[pos][d];\n        if (np == -1) {\n            if (a) sc += BOUNDARY_PENALTY;\n        } else {\n            bool b = (activeMask[st[np]] >> opp[d]) & 1u;\n            if (a && b) sc += MATCH_REWARD;\n            else if (a != b) sc += BROKEN_PENALTY;\n        }\n    }\n    return sc;\n}\n\nint calc_g(const StateArray& st) {\n    int g = 0;\n    for (int p = 0; p < P; p++) g += ownerContrib(p, st);\n    return g;\n}\n\nCycleEval evaluateCycles(const StateArray& st) {\n    CycleEval res;\n    static uint8_t vis[V];\n    static int stk[V];\n    memset(vis, 0, sizeof(vis));\n\n    int L1 = 0, L2 = 0, total = 0, numCycles = 0;\n\n    for (int p = 0; p < P; p++) {\n        uint8_t s = st[p];\n        uint8_t mask = activeMask[s];\n        int base = p << 2;\n\n        while (mask) {\n            int d = __builtin_ctz(mask);\n            mask &= mask - 1;\n            int v = base + d;\n            if (vis[v]) continue;\n\n            bool isCycle = true;\n            int vertices = 0;\n            int top = 0;\n            stk[top++] = v;\n            vis[v] = 1;\n\n            while (top) {\n                int u = stk[--top];\n                vertices++;\n\n                int pp = u >> 2;\n                int dd = u & 3;\n                uint8_t ss = st[pp];\n\n                int md = TO[ss][dd];\n                int u2 = (pp << 2) + md;\n                if (!vis[u2]) {\n                    vis[u2] = 1;\n                    stk[top++] = u2;\n                }\n\n                int np = neighborPos[pp][dd];\n                if (np != -1 && ((activeMask[st[np]] >> opp[dd]) & 1u)) {\n                    int u3 = (np << 2) + opp[dd];\n                    if (!vis[u3]) {\n                        vis[u3] = 1;\n                        stk[top++] = u3;\n                    }\n                } else {\n                    isCycle = false;\n                }\n            }\n\n            if (isCycle) {\n                int len = vertices / 2;\n                total += len;\n                numCycles++;\n                if (len > L1) {\n                    L2 = L1;\n                    L1 = len;\n                } else if (len > L2) {\n                    L2 = len;\n                }\n            }\n        }\n    }\n\n    res.L1 = L1;\n    res.L2 = L2;\n    res.total = total;\n    res.numCycles = numCycles;\n    res.score = (numCycles >= 2 ? 1LL * L1 * L2 : 0LL);\n    res.scalarNoG = res.score * SCORE_FACTOR\n                  + 1LL * res.L2 * L2_FACTOR\n                  + 1LL * res.L1 * L1_FACTOR\n                  + 2LL * res.total;\n    return res;\n}\n\nEval evaluateFull(const StateArray& st) {\n    int g = calc_g(st);\n    CycleEval c = evaluateCycles(st);\n    return make_eval(g, c);\n}\n\nvoid optimizeLocalG(StateArray& st, RNG& rng, int sweeps = 8) {\n    vector<int> order = nonDoublePos;\n    for (int sw = 0; sw < sweeps; sw++) {\n        shuffle_vec(order, rng);\n        bool changed = false;\n\n        for (int pos : order) {\n            uint8_t cur = st[pos];\n            int curScore = localCellScore(pos, cur, st);\n            int bestScore = curScore;\n            uint8_t bests[4];\n            int bc = 0;\n\n            for (int k = 0; k < allowedCnt[pos]; k++) {\n                uint8_t ns = allowedState[pos][k];\n                if (ns == cur) continue;\n                int sc = localCellScore(pos, ns, st);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bests[0] = ns;\n                    bc = 1;\n                } else if (sc == bestScore && sc > curScore) {\n                    bests[bc++] = ns;\n                }\n            }\n\n            if (bestScore > curScore) {\n                st[pos] = bests[rng.next_int(bc)];\n                changed = true;\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid optimizeG_SA(StateArray& st, RNG& rng, int steps) {\n    if (nonDoublePos.empty()) return;\n\n    int curG = calc_g(st);\n    int bestG = curG;\n    StateArray bestSt = st;\n\n    const double T0 = 4.0;\n    const double T1 = 0.03;\n\n    for (int step = 0; step < steps; step++) {\n        int pos = nonDoublePos[rng.next_int((int)nonDoublePos.size())];\n        uint8_t cur = st[pos];\n        uint8_t ns = allowedState[pos][rng.next_int(allowedCnt[pos])];\n        if (ns == cur) continue;\n\n        int before = ownerContrib(pos, st);\n        int lp = neighborPos[pos][DIR_L];\n        int up = neighborPos[pos][DIR_U];\n        if (lp != -1) before += ownerContrib(lp, st);\n        if (up != -1) before += ownerContrib(up, st);\n\n        int after = ownerContrib(pos, st, pos, ns);\n        if (lp != -1) after += ownerContrib(lp, st, pos, ns);\n        if (up != -1) after += ownerContrib(up, st, pos, ns);\n\n        int delta = after - before;\n\n        double a = (double)step / max(1, steps - 1);\n        double T = T0 * pow(T1 / T0, a);\n\n        if (delta >= 0 || rng.next_double() < exp((double)delta / T)) {\n            st[pos] = ns;\n            curG += delta;\n            if (curG > bestG) {\n                bestG = curG;\n                bestSt = st;\n            }\n        }\n    }\n\n    st = bestSt;\n}\n\nvoid addPool(vector<Candidate>& pool, const StateArray& st, int keep = 8) {\n    Candidate c;\n    c.st = st;\n    c.ev = evaluateFull(st);\n    pool.push_back(c);\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n    if ((int)pool.size() > keep) pool.resize(keep);\n}\n\nvoid applyDoublePattern(StateArray& st, int patId) {\n    for (int p : doublePos) {\n        int i = p / N, j = p % N;\n        uint8_t v = 4;\n        switch (patId) {\n            case 0: v = 4; break;\n            case 1: v = 5; break;\n            case 2: v = ((i + j) & 1) ? 4 : 5; break;\n            case 3: v = ((i + j) & 1) ? 5 : 4; break;\n            case 4: v = (i & 1) ? 4 : 5; break;\n            case 5: v = (i & 1) ? 5 : 4; break;\n            case 6: v = (j & 1) ? 4 : 5; break;\n            case 7: v = (j & 1) ? 5 : 4; break;\n            default: v = 4; break;\n        }\n        st[p] = v;\n    }\n}\n\nvoid applyDoubleRandomMode(StateArray& st, RNG& rng, int mode) {\n    if (mode == 0) {\n        for (int p : doublePos) st[p] = uint8_t(4 + rng.next_int(2));\n    } else if (mode == 1) {\n        uint8_t rowv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = rowv[p / N];\n    } else if (mode == 2) {\n        uint8_t colv[N];\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = colv[p % N];\n    } else {\n        uint8_t rowv[N], colv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(rng.next_int(2));\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(rng.next_int(2));\n        int phase = rng.next_int(2);\n        for (int p : doublePos) {\n            int i = p / N, j = p % N;\n            st[p] = uint8_t(4 + ((rowv[i] ^ colv[j] ^ phase) & 1));\n        }\n    }\n}\n\nvoid hillDoubleSingle(StateArray& st, Eval& ev, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = doublePos;\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t ns = (orig == 4 ? 5 : 4);\n            st[pos] = ns;\n\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > ev.scalar) {\n                ev.c = c2;\n                ev.scalar = sc2;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid blockDouble2x2Pass(StateArray& st, Eval& ev, RNG& rng, int passes, double deadline) {\n    vector<int> order(blocks2x2.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int bi = 0; bi < (int)order.size(); bi++) {\n            if ((bi & 31) == 0 && elapsed_sec() > deadline) break;\n            const auto& b = blocks2x2[order[bi]];\n            int ps[4], k = 0;\n            for (int t = 0; t < 4; t++) {\n                if (isDoublePos[b[t]]) ps[k++] = b[t];\n            }\n            if (k <= 1) continue;\n\n            int origMask = 0;\n            for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n            int bestMask = origMask;\n            CycleEval bestC = ev.c;\n            long long bestScalar = ev.scalar;\n\n            int lim = 1 << k;\n            for (int mask = 0; mask < lim; mask++) {\n                if (mask == origMask) continue;\n                for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestScalar) {\n                    bestScalar = sc2;\n                    bestC = c2;\n                    bestMask = mask;\n                }\n            }\n\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n            if (bestMask != origMask) {\n                ev.c = bestC;\n                ev.scalar = bestScalar;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid scanDoubleWindows23Pass(StateArray& st, Eval& ev, RNG& rng, int passes, double deadline) {\n    vector<int> order(windows23.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int wi = 0; wi < (int)order.size(); wi++) {\n            if ((wi & 31) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& w = windows23[order[wi]];\n            int ps[6], k = 0;\n            for (int t = 0; t < 6; t++) if (isDoublePos[w[t]]) ps[k++] = w[t];\n            if (k < 4) continue;\n\n            int origMask = 0;\n            for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n            int bestMask = origMask;\n            CycleEval bestC = ev.c;\n            long long bestScalar = ev.scalar;\n\n            int lim = 1 << k;\n            for (int mask = 0; mask < lim; mask++) {\n                if (mask == origMask) continue;\n                for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestScalar) {\n                    bestScalar = sc2;\n                    bestC = c2;\n                    bestMask = mask;\n                }\n            }\n\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n            if (bestMask != origMask) {\n                ev.c = bestC;\n                ev.scalar = bestScalar;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid hillExactPositions(StateArray& st, Eval& ev, const vector<int>& positions, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = positions;\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t bestState = orig;\n            Eval bestEv = ev;\n\n            if (isDoublePos[pos]) {\n                uint8_t ns = (orig == 4 ? 5 : 4);\n                st[pos] = ns;\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestEv.scalar) {\n                    bestEv.c = c2;\n                    bestEv.scalar = sc2;\n                    bestState = ns;\n                }\n            } else {\n                for (int k = 0; k < allowedCnt[pos]; k++) {\n                    uint8_t ns = allowedState[pos][k];\n                    if (ns == orig) continue;\n                    st[pos] = ns;\n                    Eval e2 = evaluateFull(st);\n                    if (e2.scalar > bestEv.scalar) {\n                        bestEv = e2;\n                        bestState = ns;\n                    }\n                }\n            }\n\n            st[pos] = bestState;\n            if (bestState != orig) {\n                ev = bestEv;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid scanAll2x2Exact(StateArray& st, Eval& ev, RNG& rng, int passes, int prodLimit, double deadline) {\n    vector<int> order(blocks2x2.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int bi = 0; bi < (int)order.size(); bi++) {\n            if ((bi & 15) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& b = blocks2x2[order[bi]];\n            int pos[4] = {b[0], b[1], b[2], b[3]};\n            int cnts[4];\n            uint8_t opts[4][4];\n            int prod = 1;\n            for (int t = 0; t < 4; t++) {\n                cnts[t] = allowedCnt[pos[t]];\n                prod *= cnts[t];\n                if (prod > prodLimit) break;\n                for (int k = 0; k < cnts[t]; k++) opts[t][k] = allowedState[pos[t]][k];\n            }\n            if (prod > prodLimit || prod <= 1) continue;\n\n            uint8_t bestStates[4];\n            for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n            Eval bestEv = ev;\n\n            for (int code = 0; code < prod; code++) {\n                int x = code;\n                for (int t = 0; t < 4; t++) {\n                    st[pos[t]] = opts[t][x % cnts[t]];\n                    x /= cnts[t];\n                }\n                Eval e2 = evaluateFull(st);\n                if (e2.scalar > bestEv.scalar) {\n                    bestEv = e2;\n                    for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n                }\n            }\n\n            for (int t = 0; t < 4; t++) st[pos[t]] = bestStates[t];\n            if (bestEv.scalar > ev.scalar) {\n                ev = bestEv;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid randomDoubleRegionSearch(StateArray& st, Eval& ev, RNG& rng, int iterations, double deadline) {\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int h = 2 + rng.next_int(2);\n        int w = 2 + rng.next_int(2);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        int ps[9];\n        int k = 0;\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) ps[k++] = p;\n            }\n        }\n        if (k <= 1 || k > 8) continue;\n\n        int origMask = 0;\n        for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n        int bestMask = origMask;\n        CycleEval bestC = ev.c;\n        long long bestScalar = ev.scalar;\n\n        int lim = 1 << k;\n        for (int mask = 0; mask < lim; mask++) {\n            if (mask == origMask) continue;\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > bestScalar) {\n                bestScalar = sc2;\n                bestC = c2;\n                bestMask = mask;\n            }\n        }\n\n        for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n        if (bestMask != origMask) {\n            ev.c = bestC;\n            ev.scalar = bestScalar;\n        }\n    }\n}\n\nvector<int> buildNeighborhood(const vector<int>& touched) {\n    if (++curStampCell == INT_MAX) {\n        memset(seenStampCell, 0, sizeof(seenStampCell));\n        curStampCell = 1;\n    }\n    vector<int> res;\n    res.reserve(touched.size() * 5 + 8);\n\n    auto add = [&](int p) {\n        if (p < 0 || p >= P) return;\n        if (seenStampCell[p] == curStampCell) return;\n        seenStampCell[p] = curStampCell;\n        res.push_back(p);\n    };\n\n    for (int p : touched) {\n        add(p);\n        for (int d = 0; d < 4; d++) {\n            int np = neighborPos[p][d];\n            if (np != -1) add(np);\n        }\n    }\n    return res;\n}\n\nvector<int> buildBlocksAroundTouched(const vector<int>& touched) {\n    if (++curStampBlock == INT_MAX) {\n        memset(seenStampBlock, 0, sizeof(seenStampBlock));\n        curStampBlock = 1;\n    }\n    vector<int> res;\n    res.reserve(touched.size() * 4 + 8);\n\n    for (int p : touched) {\n        int i = p / N, j = p % N;\n        int i0 = max(0, i - 1), i1 = min(N - 2, i);\n        int j0 = max(0, j - 1), j1 = min(N - 2, j);\n        for (int bi = i0; bi <= i1; bi++) {\n            for (int bj = j0; bj <= j1; bj++) {\n                int id = bi * (N - 1) + bj;\n                if (seenStampBlock[id] == curStampBlock) continue;\n                seenStampBlock[id] = curStampBlock;\n                res.push_back(id);\n            }\n        }\n    }\n    return res;\n}\n\nvoid scan2x2BlockIdsExact(StateArray& st, Eval& ev, const vector<int>& ids, int prodLimit, RNG& rng, double deadline) {\n    vector<int> order = ids;\n    shuffle_vec(order, rng);\n    bool improved = true;\n\n    for (int pass = 0; pass < 2 && improved; pass++) {\n        improved = false;\n        for (int tbi = 0; tbi < (int)order.size(); tbi++) {\n            if ((tbi & 15) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& b = blocks2x2[order[tbi]];\n            int pos[4] = {b[0], b[1], b[2], b[3]};\n            int cnts[4];\n            uint8_t opts[4][4];\n            int prod = 1;\n            for (int t = 0; t < 4; t++) {\n                cnts[t] = allowedCnt[pos[t]];\n                prod *= cnts[t];\n                if (prod > prodLimit) break;\n                for (int k = 0; k < cnts[t]; k++) opts[t][k] = allowedState[pos[t]][k];\n            }\n            if (prod > prodLimit || prod <= 1) continue;\n\n            uint8_t bestStates[4];\n            for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n            Eval bestEv = ev;\n\n            for (int code = 0; code < prod; code++) {\n                int x = code;\n                for (int t = 0; t < 4; t++) {\n                    st[pos[t]] = opts[t][x % cnts[t]];\n                    x /= cnts[t];\n                }\n                Eval e2 = evaluateFull(st);\n                if (e2.scalar > bestEv.scalar) {\n                    bestEv = e2;\n                    for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n                }\n            }\n\n            for (int t = 0; t < 4; t++) st[pos[t]] = bestStates[t];\n            if (bestEv.scalar > ev.scalar) {\n                ev = bestEv;\n                improved = true;\n            }\n        }\n    }\n}\n\nvoid perturb(StateArray& st, RNG& rng, int strength, vector<int>& touched) {\n    touched.clear();\n    auto touch = [&](int p) { touched.push_back(p); };\n\n    int mode = rng.next_int(100);\n\n    if (mode < 55 && !doublePos.empty()) {\n        int h = 2 + rng.next_int(3);\n        int w = 2 + rng.next_int(3);\n        h = min(h, N);\n        w = min(w, N);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) {\n                    if (rng.next_int(100) < 80) {\n                        st[p] = (st[p] == 4 ? 5 : 4);\n                        touch(p);\n                    }\n                } else if (rng.next_int(100) < 20) {\n                    uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n                    if (ns != st[p]) {\n                        st[p] = ns;\n                        touch(p);\n                    }\n                }\n            }\n        }\n    } else {\n        int moves = 3 + rng.next_int(4) + min(8, strength / 4);\n        for (int t = 0; t < moves; t++) {\n            int p = rng.next_int(P);\n            uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n            if (ns != st[p]) {\n                st[p] = ns;\n                touch(p);\n            }\n        }\n    }\n\n    if (touched.empty()) {\n        int p = rng.next_int(P);\n        uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n        if (ns != st[p]) st[p] = ns;\n        touch(p);\n    }\n}\n\n// ---------- crossover helpers ----------\n\nbool tryCopyDoublesFromDonor(StateArray& st, Eval& ev, const StateArray& donor,\n                             const vector<int>& posList, vector<int>* touched) {\n    vector<int> changed;\n    changed.reserve(posList.size());\n    for (int p : posList) {\n        if (!isDoublePos[p]) continue;\n        if (st[p] != donor[p]) {\n            changed.push_back(p);\n            st[p] = donor[p];\n        }\n    }\n    if (changed.empty()) return false;\n\n    CycleEval c2 = evaluateCycles(st);\n    long long sc2 = make_scalar(c2, ev.g);\n    if (sc2 > ev.scalar) {\n        ev.c = c2;\n        ev.scalar = sc2;\n        if (touched) {\n            for (int p : changed) touched->push_back(p);\n        }\n        return true;\n    }\n\n    for (int p : changed) st[p] = (donor[p] == 4 ? 5 : 4);\n    return false;\n}\n\nvoid greedyBandCrossoverDoubles(StateArray& st, Eval& ev, const StateArray& donor,\n                                RNG& rng, vector<int>& touched, double deadline) {\n    struct Band { int type, idx; };\n    vector<Band> bands;\n    bands.reserve(30 + 30 + 29 + 29);\n    for (int r = 0; r < N; r++) bands.push_back({0, r});\n    for (int c = 0; c < N; c++) bands.push_back({1, c});\n    for (int r = 0; r + 1 < N; r++) bands.push_back({2, r});\n    for (int c = 0; c + 1 < N; c++) bands.push_back({3, c});\n    shuffle_vec(bands, rng);\n\n    vector<int> pos;\n    pos.reserve(2 * N);\n\n    for (int bi = 0; bi < (int)bands.size(); bi++) {\n        if ((bi & 7) == 0 && elapsed_sec() > deadline) break;\n        pos.clear();\n\n        int type = bands[bi].type;\n        int idx = bands[bi].idx;\n        if (type == 0) {\n            int i = idx;\n            for (int j = 0; j < N; j++) pos.push_back(i * N + j);\n        } else if (type == 1) {\n            int j = idx;\n            for (int i = 0; i < N; i++) pos.push_back(i * N + j);\n        } else if (type == 2) {\n            int i = idx;\n            for (int j = 0; j < N; j++) {\n                pos.push_back(i * N + j);\n                pos.push_back((i + 1) * N + j);\n            }\n        } else {\n            int j = idx;\n            for (int i = 0; i < N; i++) {\n                pos.push_back(i * N + j);\n                pos.push_back(i * N + (j + 1));\n            }\n        }\n\n        tryCopyDoublesFromDonor(st, ev, donor, pos, &touched);\n    }\n}\n\nvoid randomRectCrossoverDoubles(StateArray& st, Eval& ev, const StateArray& donor,\n                                RNG& rng, int iters, vector<int>& touched, double deadline) {\n    vector<int> pos;\n    pos.reserve(P);\n\n    for (int it = 0; it < iters; it++) {\n        if ((it & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int h = 2 + rng.next_int(7);\n        int w = 2 + rng.next_int(7);\n        if (rng.next_int(100) < 20) {\n            h = 2 + rng.next_int(11);\n            w = 2 + rng.next_int(11);\n        }\n        h = min(h, N);\n        w = min(w, N);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        pos.clear();\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                pos.push_back(i * N + j);\n            }\n        }\n        tryCopyDoublesFromDonor(st, ev, donor, pos, &touched);\n    }\n}\n\nbool tryAllPatchWithRepair(StateArray& st, Eval& ev, const StateArray& donor,\n                           const vector<int>& patch, RNG& rng, double deadline,\n                           vector<int>* touchedAccum) {\n    vector<int> changed;\n    changed.reserve(patch.size());\n    for (int p : patch) {\n        if (st[p] != donor[p]) {\n            changed.push_back(p);\n        }\n    }\n    if (changed.empty()) return false;\n\n    StateArray tmp = st;\n    for (int p : changed) tmp[p] = donor[p];\n    Eval tev = evaluateFull(tmp);\n\n    vector<int> neigh = buildNeighborhood(changed);\n    hillExactPositions(tmp, tev, neigh, rng, 1, deadline);\n    vector<int> blockIds = buildBlocksAroundTouched(changed);\n    scan2x2BlockIdsExact(tmp, tev, blockIds, 96, rng, deadline);\n\n    if (tev.scalar > ev.scalar) {\n        st = tmp;\n        ev = tev;\n        if (touchedAccum) {\n            for (int p : changed) touchedAccum->push_back(p);\n        }\n        return true;\n    }\n    return false;\n}\n\nvoid randomPatchCrossoverAll(StateArray& st, Eval& ev, const StateArray& donor,\n                             RNG& rng, int trials, vector<int>& touched, double deadline) {\n    vector<int> patch;\n    patch.reserve(P);\n\n    for (int it = 0; it < trials; it++) {\n        if (elapsed_sec() > deadline) break;\n        patch.clear();\n\n        int mode = rng.next_int(100);\n        if (mode < 35) {\n            int h = 1 + rng.next_int(3);\n            int si = rng.next_int(N - h + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = 0; j < N; j++) patch.push_back(i * N + j);\n            }\n        } else if (mode < 70) {\n            int w = 1 + rng.next_int(3);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = 0; i < N; i++) {\n                for (int j = sj; j < sj + w; j++) patch.push_back(i * N + j);\n            }\n        } else {\n            int h = 2 + rng.next_int(6);\n            int w = 2 + rng.next_int(6);\n            if (rng.next_int(100) < 25) {\n                h = 2 + rng.next_int(9);\n                w = 2 + rng.next_int(9);\n            }\n            h = min(h, N);\n            w = min(w, N);\n            int si = rng.next_int(N - h + 1);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = sj; j < sj + w; j++) patch.push_back(i * N + j);\n            }\n        }\n\n        tryAllPatchWithRepair(st, ev, donor, patch, rng, deadline, &touched);\n    }\n}\n\nbool makeCrossoverChild(const Candidate& base, const Candidate& donor,\n                        StateArray& child, Eval& ev, RNG& rng,\n                        vector<int>& touched, double deadline) {\n    child = base.st;\n    ev = base.ev;\n    touched.clear();\n\n    greedyBandCrossoverDoubles(child, ev, donor.st, rng, touched, deadline);\n    randomRectCrossoverDoubles(child, ev, donor.st, rng, 12, touched, deadline);\n\n    if (rng.next_int(100) < 60) {\n        randomPatchCrossoverAll(child, ev, donor.st, rng, 2, touched, deadline);\n    }\n\n    return !touched.empty();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n    init_tables();\n\n    uint64_t seed = 1469598103934665603ULL;\n    vector<string> S(N);\n    for (int i = 0; i < N; i++) {\n        cin >> S[i];\n        for (char c : S[i]) {\n            seed ^= uint64_t((unsigned char)c + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    RNG rng(seed);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            int b = S[i][j] - '0';\n            baseTile[p] = (uint8_t)b;\n            isDoublePos[p] = (b == 4 || b == 5);\n            allPos.push_back(p);\n            if (isDoublePos[p]) doublePos.push_back(p);\n            else nonDoublePos.push_back(p);\n\n            int cnt = 0;\n            for (int s = 0; s < 8; s++) {\n                if (stateToRot[b][s] != 255) {\n                    allowedState[p][cnt++] = (uint8_t)s;\n                }\n            }\n            allowedCnt[p] = (uint8_t)cnt;\n        }\n    }\n\n    const double deadline = 1.95;\n\n    vector<Candidate> pool;\n    int baseStarts = 7;\n\n    for (int it = 0; it < baseStarts; it++) {\n        if (elapsed_sec() > 0.38) break;\n\n        StateArray base{};\n        for (int p = 0; p < P; p++) {\n            if (isDoublePos[p]) base[p] = 4;\n            else base[p] = allowedState[p][rng.next_int(allowedCnt[p])];\n        }\n\n        optimizeLocalG(base, rng, 6);\n        optimizeG_SA(base, rng, 18000);\n        optimizeLocalG(base, rng, 4);\n\n        for (int pat = 0; pat < 8; pat++) {\n            StateArray cand = base;\n            applyDoublePattern(cand, pat);\n            addPool(pool, cand, 8);\n        }\n        for (int mode = 0; mode < 4; mode++) {\n            StateArray cand = base;\n            applyDoubleRandomMode(cand, rng, mode);\n            addPool(pool, cand, 8);\n        }\n    }\n\n    if (pool.empty()) {\n        StateArray st{};\n        for (int p = 0; p < P; p++) st[p] = allowedState[p][0];\n        addPool(pool, st, 8);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    int refineCount = min<int>(3, pool.size());\n    for (int i = 0; i < refineCount; i++) {\n        if (elapsed_sec() > 1.00) break;\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n        blockDouble2x2Pass(pool[i].st, pool[i].ev, rng, 1, deadline);\n        if (i < 2) scanDoubleWindows23Pass(pool[i].st, pool[i].ev, rng, 1, deadline);\n        if (i < 2) hillExactPositions(pool[i].st, pool[i].ev, allPos, rng, 1, deadline);\n        if (i == 0 && elapsed_sec() < 1.38) {\n            scanAll2x2Exact(pool[i].st, pool[i].ev, rng, 1, 64, deadline);\n        }\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    int topMix = min<int>(3, pool.size());\n    for (int a = 0; a < topMix; a++) {\n        for (int b = 0; b < topMix; b++) {\n            if (a == b) continue;\n            if (elapsed_sec() > 1.48) break;\n\n            StateArray child;\n            Eval ev;\n            vector<int> touched;\n            if (!makeCrossoverChild(pool[a], pool[b], child, ev, rng, touched, deadline)) continue;\n\n            vector<int> neigh = buildNeighborhood(touched);\n            hillExactPositions(child, ev, neigh, rng, 1, deadline);\n            vector<int> blockIds = buildBlocksAroundTouched(touched);\n            scan2x2BlockIdsExact(child, ev, blockIds, 128, rng, deadline);\n            hillDoubleSingle(child, ev, rng, 1, deadline);\n            if (rng.next_int(100) < 60) blockDouble2x2Pass(child, ev, rng, 1, deadline);\n\n            Candidate c;\n            c.st = child;\n            c.ev = ev;\n            pool.push_back(c);\n            sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n                return x.ev.scalar > y.ev.scalar;\n            });\n            if ((int)pool.size() > 8) pool.resize(8);\n        }\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    Candidate best = pool[0];\n    Candidate current = best;\n    int stagnation = 0;\n\n    while (elapsed_sec() < deadline - 0.16) {\n        StateArray trial;\n        Eval tev;\n        vector<int> touched;\n\n        bool useCross = (stagnation >= 8 && (int)pool.size() >= 2 && rng.next_int(100) < 45);\n\n        if (useCross) {\n            int lim = min<int>(4, pool.size());\n            int ia = rng.next_int(lim);\n            int ib = rng.next_int(lim - 1);\n            if (ib >= ia) ib++;\n            if (!makeCrossoverChild(pool[ia], pool[ib], trial, tev, rng, touched, deadline)) {\n                trial = pool[ia].st;\n                tev = pool[ia].ev;\n                perturb(trial, rng, stagnation, touched);\n                tev = evaluateFull(trial);\n            }\n        } else {\n            trial = (rng.next_int(100) < 60 ? current.st : best.st);\n            perturb(trial, rng, stagnation, touched);\n            tev = evaluateFull(trial);\n        }\n\n        vector<int> neigh = buildNeighborhood(touched);\n        hillExactPositions(trial, tev, neigh, rng, 1, deadline);\n\n        vector<int> blockIds = buildBlocksAroundTouched(touched);\n        scan2x2BlockIdsExact(trial, tev, blockIds, 128, rng, deadline);\n\n        randomDoubleRegionSearch(trial, tev, rng, 12, deadline);\n        hillDoubleSingle(trial, tev, rng, 1, deadline);\n        if (rng.next_int(100) < 30) blockDouble2x2Pass(trial, tev, rng, 1, deadline);\n\n        if (tev.scalar > best.ev.scalar) {\n            best.st = trial;\n            best.ev = tev;\n            current = best;\n            stagnation = 0;\n            pool.push_back(best);\n            sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n                return a.ev.scalar > b.ev.scalar;\n            });\n            if ((int)pool.size() > 8) pool.resize(8);\n        } else {\n            stagnation++;\n        }\n\n        if (tev.scalar > current.ev.scalar || rng.next_int(100) < (stagnation < 10 ? 18 : 30)) {\n            current.st = trial;\n            current.ev = tev;\n        }\n\n        if (stagnation >= 20 && !pool.empty()) {\n            current = pool[rng.next_int((int)pool.size())];\n            stagnation = 0;\n        }\n    }\n\n    hillDoubleSingle(best.st, best.ev, rng, 2, deadline);\n    blockDouble2x2Pass(best.st, best.ev, rng, 2, deadline);\n    if (elapsed_sec() < deadline - 0.12) scanDoubleWindows23Pass(best.st, best.ev, rng, 1, deadline);\n    if (elapsed_sec() < deadline - 0.07) scanAll2x2Exact(best.st, best.ev, rng, 1, 64, deadline);\n    if (elapsed_sec() < deadline - 0.03) hillExactPositions(best.st, best.ev, allPos, rng, 1, deadline);\n    hillDoubleSingle(best.st, best.ev, rng, 1, deadline);\n\n    string ans;\n    ans.resize(P);\n    for (int p = 0; p < P; p++) {\n        uint8_t r = stateToRot[baseTile[p]][best.st[p]];\n        if (r == 255) r = 0;\n        ans[p] = char('0' + r);\n    }\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nstatic constexpr int MAXC = 100;\nstatic constexpr uint16_t NIL = 65535;\n\nstruct FastHash {\n    static ull splitmix64(ull 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()(ull x) const {\n        static const ull FIXED_RANDOM =\n            chrono::steady_clock::now().time_since_epoch().count();\n        return (size_t)splitmix64(x + FIXED_RANDOM);\n    }\n};\n\nstruct Metrics {\n    int tree = 1;\n    int largest_comp = 1;\n    int matched = 0;\n    int components = 1;\n    int cycle_excess = 0;\n    int full_tiles = 0;\n    int sumsq = 1;\n    int pot_max = 1;\n    int pot_sum = 1;\n    int hole_bad = 0;\n    int dist = 0;\n};\n\nstruct Node {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1; // 0:U 1:D 2:L 3:R\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct Cand {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1;\n    uint16_t parent = NIL;\n    char mv = '?';\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct SearchResult {\n    string best_tree_path;\n    int best_tree = 1;\n    string best_mode_path;\n    long long best_mode_score = LLONG_MIN;\n};\n\nstruct Solver {\n    int N, T, NN, FULL;\n    array<int, MAXC> nxtU, nxtD, nxtL, nxtR;\n    array<array<int, MAXC>, 4> nxtPos{};\n    array<int, MAXC> rr{}, cc{};\n    array<array<ull, 16>, MAXC> zob{};\n    ull lastSalt[5]{};\n    int popc[16]{};\n\n    chrono::steady_clock::time_point st;\n    double total_limit_sec = 2.82;\n\n    static ull splitmix64_ref(ull &x) {\n        ull z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool time_over(double deadline) const {\n        return elapsed() >= deadline;\n    }\n\n    static int hexval(char c) {\n        if ('0' <= c && c <= '9') return c - '0';\n        return c - 'a' + 10;\n    }\n\n    static int char_to_dir(char c) {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        return 3; // R\n    }\n\n    ull state_key(ull h, int last) const {\n        return h ^ lastSalt[last + 1];\n    }\n\n    string build_path(int depth, int idx,\n                      const vector<vector<uint16_t>> &parents,\n                      const vector<vector<char>> &moves) const {\n        string res(depth, '?');\n        while (depth > 0) {\n            res[depth - 1] = moves[depth][idx];\n            idx = parents[depth][idx];\n            --depth;\n        }\n        return res;\n    }\n\n    Metrics evaluate(const array<unsigned char, MAXC> &b, int blank) const {\n        int parent[MAXC];\n        int sz[MAXC];\n        int ed[MAXC];\n        unsigned char mdeg[MAXC];\n\n        for (int i = 0; i < NN; i++) {\n            mdeg[i] = 0;\n            if (b[i] == 0) {\n                parent[i] = -1;\n                sz[i] = 0;\n                ed[i] = 0;\n            } else {\n                parent[i] = i;\n                sz[i] = 1;\n                ed[i] = 0;\n            }\n        }\n\n        auto find = [&](int x) {\n            while (parent[x] != x) {\n                parent[x] = parent[parent[x]];\n                x = parent[x];\n            }\n            return x;\n        };\n\n        auto unite_edge = [&](int a, int c) {\n            int ra = find(a), rb = find(c);\n            if (ra == rb) {\n                ed[ra]++;\n            } else {\n                if (sz[ra] < sz[rb]) swap(ra, rb);\n                parent[rb] = ra;\n                sz[ra] += sz[rb];\n                ed[ra] += ed[rb] + 1;\n            }\n        };\n\n        Metrics m;\n        m.tree = 1;\n        m.largest_comp = 1;\n        m.matched = 0;\n        m.components = 0;\n        m.cycle_excess = 0;\n        m.full_tiles = 0;\n        m.sumsq = 0;\n        m.pot_max = 1;\n        m.pot_sum = 0;\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n\n            int r = nxtR[i];\n            if (r != -1) {\n                unsigned char tr = b[r];\n                if ((t & 4) && (tr & 1)) {\n                    unite_edge(i, r);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[r]++;\n                }\n            }\n\n            int d = nxtD[i];\n            if (d != -1) {\n                unsigned char td = b[d];\n                if ((t & 8) && (td & 2)) {\n                    unite_edge(i, d);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[d]++;\n                }\n            }\n        }\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n            if ((int)mdeg[i] == popc[t]) m.full_tiles++;\n        }\n\n        for (int i = 0; i < NN; i++) {\n            if (parent[i] == i) {\n                m.components++;\n                int v = sz[i];\n                int ex = ed[i] - v + 1;\n                if (ex < 0) ex = 0;\n                m.cycle_excess += ex;\n                m.largest_comp = max(m.largest_comp, v);\n                if (ed[i] == v - 1) m.tree = max(m.tree, v);\n                m.sumsq += v * v;\n                int pot = v - 2 * ex;\n                if (pot < 0) pot = 0;\n                m.pot_max = max(m.pot_max, pot);\n                m.pot_sum += pot;\n            }\n        }\n\n        // hole conflicts: stubs pointing into the blank\n        m.hole_bad = 0;\n        int u = nxtU[blank], d = nxtD[blank], l = nxtL[blank], r = nxtR[blank];\n        if (u != -1 && (b[u] & 8)) m.hole_bad++;\n        if (d != -1 && (b[d] & 2)) m.hole_bad++;\n        if (l != -1 && (b[l] & 4)) m.hole_bad++;\n        if (r != -1 && (b[r] & 1)) m.hole_bad++;\n\n        m.dist = (N - 1 - rr[blank]) + (N - 1 - cc[blank]);\n\n        return m;\n    }\n\n    long long score_of(const Metrics &m, int mode) const {\n        if (mode == 0) {\n            // Global completion-oriented:\n            // fewer cycles/components via matched-3*cycles,\n            // more fully satisfied tiles, bigger merged regions.\n            return\n                1'000'000'000'000LL * (m.matched - 3 * m.cycle_excess) +\n                1'000'000'000LL * m.full_tiles +\n                100'000LL * m.sumsq +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        } else if (mode == 1) {\n            // Large near-tree component.\n            return\n                1'000'000'000'000LL * m.pot_max +\n                1'000'000'000LL * m.tree +\n                1'000'000LL * (m.matched - 2 * m.cycle_excess) +\n                1'000LL * m.full_tiles +\n                m.largest_comp -\n                10LL * m.hole_bad;\n        } else {\n            // Local consistency.\n            return\n                1'000'000'000'000LL * m.full_tiles +\n                1'000'000'000LL * m.matched +\n                1'000'000LL * m.pot_sum +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        }\n    }\n\n    SearchResult beam_search(const array<unsigned char, MAXC> &start_board,\n                             int start_blank,\n                             int depth_limit,\n                             int mode,\n                             int width,\n                             double deadline,\n                             int start_last = -1,\n                             ull tie_salt = 0) {\n        SearchResult res;\n\n        Node root;\n        root.b = start_board;\n        root.blank = start_blank;\n        root.last = (signed char)start_last;\n        root.h = 0;\n        for (int i = 0; i < NN; i++) root.h ^= zob[i][root.b[i]];\n\n        Metrics rm = evaluate(root.b, root.blank);\n        root.tree = (short)rm.tree;\n        root.score = score_of(rm, mode);\n\n        res.best_tree = root.tree;\n        res.best_tree_path = \"\";\n        res.best_mode_score = root.score;\n        res.best_mode_path = \"\";\n\n        if (root.tree == FULL || depth_limit == 0) return res;\n\n        vector<Node> cur, next;\n        cur.reserve(width);\n        next.reserve(width);\n        cur.push_back(root);\n\n        vector<vector<uint16_t>> parents(depth_limit + 1);\n        vector<vector<char>> moves(depth_limit + 1);\n        parents[0].push_back(NIL);\n        moves[0].push_back('?');\n\n        unordered_set<ull, FastHash> seen;\n        {\n            size_t est = (size_t)min<long long>((long long)width * min(depth_limit, 1500) + 1024LL, 2'000'000LL);\n            seen.reserve(est * 2 + 1);\n            seen.max_load_factor(0.7f);\n        }\n        seen.insert(state_key(root.h, root.last));\n\n        const int inv[4] = {1, 0, 3, 2};\n        const char dirc[4] = {'U', 'D', 'L', 'R'};\n\n        vector<Cand> cands;\n        cands.reserve(width * 3 + 8);\n\n        int blankCap = (N <= 7 ? 12 : 8);\n        int blankLastCap = 3;\n\n        for (int depth = 0; depth < depth_limit; depth++) {\n            if (time_over(deadline)) break;\n\n            cands.clear();\n\n            for (int pi = 0; pi < (int)cur.size(); pi++) {\n                if ((pi & 31) == 0 && time_over(deadline)) break;\n                const Node &nd = cur[pi];\n\n                for (int dir = 0; dir < 4; dir++) {\n                    if (nd.last != -1 && inv[dir] == nd.last) continue;\n                    int nb = nxtPos[dir][nd.blank];\n                    if (nb == -1) continue;\n\n                    unsigned char tile = nd.b[nb];\n                    ull nh = nd.h ^ zob[nd.blank][0] ^ zob[nb][tile] ^ zob[nd.blank][tile] ^ zob[nb][0];\n                    ull key = state_key(nh, dir);\n                    if (seen.find(key) != seen.end()) continue;\n\n                    Cand cd;\n                    cd.b = nd.b;\n                    cd.b[nd.blank] = tile;\n                    cd.b[nb] = 0;\n                    cd.h = nh;\n                    cd.blank = nb;\n                    cd.last = (signed char)dir;\n                    cd.parent = (uint16_t)pi;\n                    cd.mv = dirc[dir];\n\n                    Metrics m = evaluate(cd.b, cd.blank);\n                    cd.tree = (short)m.tree;\n                    cd.score = score_of(m, mode);\n\n                    cands.push_back(std::move(cd));\n\n                    if (m.tree > res.best_tree) {\n                        res.best_tree = m.tree;\n                        res.best_tree_path = build_path(depth, pi, parents, moves);\n                        res.best_tree_path.push_back(dirc[dir]);\n                        if (m.tree == FULL) return res;\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand &a, const Cand &b) {\n                if (a.score != b.score) return a.score > b.score;\n                return (a.h ^ tie_salt) < (b.h ^ tie_salt);\n            });\n\n            unordered_set<ull, FastHash> used;\n            used.reserve(cands.size() * 2 + 1);\n            used.max_load_factor(0.7f);\n\n            vector<unsigned char> blankCnt(NN, 0);\n            vector<array<unsigned char, 4>> blankLastCnt(NN);\n            for (int i = 0; i < NN; i++) blankLastCnt[i] = {0, 0, 0, 0};\n\n            next.clear();\n            parents[depth + 1].clear();\n            moves[depth + 1].clear();\n            next.reserve(width);\n            parents[depth + 1].reserve(width);\n            moves[depth + 1].reserve(width);\n\n            auto try_add = [&](const Cand &cd, bool use_cap) -> bool {\n                ull key = state_key(cd.h, cd.last);\n                if (used.find(key) != used.end()) return false;\n                if (seen.find(key) != seen.end()) return false;\n\n                if (use_cap) {\n                    if (blankCnt[cd.blank] >= blankCap) return false;\n                    if (blankLastCnt[cd.blank][cd.last] >= blankLastCap) return false;\n                }\n\n                used.insert(key);\n                seen.insert(key);\n                blankCnt[cd.blank]++;\n                blankLastCnt[cd.blank][cd.last]++;\n\n                Node nd;\n                nd.b = cd.b;\n                nd.h = cd.h;\n                nd.blank = cd.blank;\n                nd.last = cd.last;\n                nd.tree = cd.tree;\n                nd.score = cd.score;\n                next.push_back(std::move(nd));\n                parents[depth + 1].push_back(cd.parent);\n                moves[depth + 1].push_back(cd.mv);\n\n                if (cd.score > res.best_mode_score) {\n                    res.best_mode_score = cd.score;\n                    res.best_mode_path = build_path(depth + 1, (int)next.size() - 1, parents, moves);\n                }\n                return true;\n            };\n\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, true);\n            }\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, false);\n            }\n\n            if (next.empty()) break;\n            cur.swap(next);\n        }\n\n        return res;\n    }\n\n    void apply_moves(array<unsigned char, MAXC> &b, int &blank, const string &path) const {\n        for (char c : path) {\n            int dir = char_to_dir(c);\n            int nb = nxtPos[dir][blank];\n            unsigned char tile = b[nb];\n            b[blank] = tile;\n            b[nb] = 0;\n            blank = nb;\n        }\n    }\n\n    bool better_solution(int treeA, int lenA, int treeB, int lenB) const {\n        if (treeA != treeB) return treeA > treeB;\n        if (treeA == FULL && treeB == FULL) return lenA < lenB;\n        return false;\n    }\n\n    int base_width() const {\n        if (N <= 6) return 2200;\n        if (N == 7) return 1600;\n        if (N == 8) return 950;\n        if (N == 9) return 650;\n        return 450;\n    }\n\n    void solve() {\n        cin >> N >> T;\n        NN = N * N;\n        FULL = NN - 1;\n\n        array<unsigned char, MAXC> init_board{};\n        int init_blank = -1;\n        for (int i = 0; i < N; i++) {\n            string s;\n            cin >> s;\n            for (int j = 0; j < N; j++) {\n                int v = hexval(s[j]);\n                init_board[i * N + j] = (unsigned char)v;\n                if (v == 0) init_blank = i * N + j;\n            }\n        }\n\n        for (int i = 0; i < 16; i++) popc[i] = __builtin_popcount(i);\n\n        for (int i = 0; i < NN; i++) {\n            int r = i / N, c = i % N;\n            rr[i] = r;\n            cc[i] = c;\n            nxtU[i] = (r > 0 ? i - N : -1);\n            nxtD[i] = (r + 1 < N ? i + N : -1);\n            nxtL[i] = (c > 0 ? i - 1 : -1);\n            nxtR[i] = (c + 1 < N ? i + 1 : -1);\n            nxtPos[0][i] = nxtU[i];\n            nxtPos[1][i] = nxtD[i];\n            nxtPos[2][i] = nxtL[i];\n            nxtPos[3][i] = nxtR[i];\n        }\n\n        ull seed = 0x123456789abcdef0ULL;\n        for (int i = 0; i < NN; i++) {\n            for (int v = 0; v < 16; v++) zob[i][v] = splitmix64_ref(seed);\n        }\n        for (int i = 0; i < 5; i++) lastSalt[i] = splitmix64_ref(seed);\n\n        st = chrono::steady_clock::now();\n\n        Metrics initM = evaluate(init_board, init_blank);\n        string best_path = \"\";\n        int best_tree = initM.tree;\n\n        int W = base_width();\n\n        double d1 = total_limit_sec * 0.40;\n        double d2 = total_limit_sec * 0.72;\n        double d3 = total_limit_sec * 0.90;\n        double d4 = total_limit_sec - 0.02;\n\n        ull salt1 = splitmix64_ref(seed);\n        ull salt2 = splitmix64_ref(seed);\n        ull salt3 = splitmix64_ref(seed);\n        ull salt4 = splitmix64_ref(seed);\n\n        SearchResult r0, r1;\n\n        // Run 1: global-completion beam\n        if (!time_over(d1)) {\n            r0 = beam_search(init_board, init_blank, T, 0, W, d1, -1, salt1);\n            if (better_solution(r0.best_tree, (int)r0.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r0.best_tree;\n                best_path = r0.best_tree_path;\n            }\n        }\n\n        // Run 2: big-near-tree beam\n        if (!time_over(d2)) {\n            r1 = beam_search(init_board, init_blank, T, 1, (W * 3) / 4, d2, -1, salt2);\n            if (better_solution(r1.best_tree, (int)r1.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r1.best_tree;\n                best_path = r1.best_tree_path;\n            }\n        }\n\n        // Choose a promising intermediate path for refinement.\n        vector<string> candidates;\n        candidates.push_back(best_path);\n        candidates.push_back(r0.best_mode_path);\n        candidates.push_back(r1.best_mode_path);\n        candidates.push_back(r0.best_tree_path);\n        candidates.push_back(r1.best_tree_path);\n\n        sort(candidates.begin(), candidates.end());\n        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());\n\n        string refine_start = best_path;\n        long long refine_best_score = LLONG_MIN;\n        int refine_best_len = (int)best_path.size();\n\n        for (const string &p : candidates) {\n            if ((int)p.size() > T) continue;\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, p);\n            Metrics m = evaluate(b, blank);\n            long long sc = score_of(m, 0); // completion-oriented\n            if (sc > refine_best_score || (sc == refine_best_score && (int)p.size() < refine_best_len)) {\n                refine_best_score = sc;\n                refine_best_len = (int)p.size();\n                refine_start = p;\n            }\n        }\n\n        // Refinement 1 from the most completion-promising state.\n        if (!time_over(d3) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, refine_start);\n            int rem = T - (int)refine_start.size();\n            int stlast = refine_start.empty() ? -1 : char_to_dir(refine_start.back());\n            if (rem > 0) {\n                auto rr0 = beam_search(b, blank, rem, 0, (W * 2) / 3, d3, stlast, salt3);\n                string cand_path = refine_start + rr0.best_tree_path;\n                if (better_solution(rr0.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr0.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        // Refinement 2 from current best tree state, slightly different heuristic.\n        if (!time_over(d4) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, best_path);\n            int rem = T - (int)best_path.size();\n            int stlast = best_path.empty() ? -1 : char_to_dir(best_path.back());\n            if (rem > 0) {\n                auto rr1 = beam_search(b, blank, rem, 1, max(120, W / 2), d4, stlast, salt4);\n                string cand_path = best_path + rr1.best_tree_path;\n                if (better_solution(rr1.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr1.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        cout << best_path << '\\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}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int R = 10000;\nstatic constexpr int MAX_CUTS = 100;\nstatic constexpr int NORMAL_MAX = 4096;\nstatic constexpr int MIN_NORM = 1000;\nstatic constexpr long double SQRT3 = 1.7320508075688772935L;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Line {\n    int A, B; // primitive, sign-normalized\n    ll C;     // A x + B y = C\n};\n\nstruct State {\n    vector<int> cell;      // cell id for each point\n    vector<int> cellSize;  // strawberries per cell\n    array<int, 11> hist{}; // hist[d] = #cells with d strawberries\n    int rawScore = 0;      // sum min(a_d, hist[d])\n    int smallCount = 0;    // #cells with size 1..10\n    int mass10 = 0;        // sum min(cell_size, 10)\n};\n\nstruct Cand2 {\n    int A, B;\n    int t1, t2;\n    double alpha1, alpha2;\n    double off1, off2;\n};\n\nstruct Cand3 {\n    array<pair<int,int>,3> n;\n    int t[3];\n    double alpha[3];\n    double off[3];\n};\n\nstruct BestLineRes {\n    bool ok = false;\n    int raw = -1000000000;\n    int mass10 = -1000000000;\n    int small = -1000000000;\n    Line line{};\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed ? seed : 88172645463393265ull) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double uniform() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    double uniform(double l, double r) {\n        return l + (r - l) * uniform();\n    }\n    ll next_ll(ll l, ll r) {\n        if (l > r) swap(l, r);\n        unsigned long long w = (unsigned long long)(r - l + 1);\n        return l + (ll)(next() % w);\n    }\n    int next_int(int l, int r) {\n        return (int)next_ll(l, r);\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\nint N, K;\nint a_need[11];\nint attendees_sum = 0;\nvector<Pt> pts;\nXorShift64 rng;\n\ntemplate <class T>\nT clampv(T x, T l, T r) {\n    return min(r, max(l, x));\n}\n\nstatic inline ll proj(int A, int B, const Pt& p) {\n    return 1LL * A * p.x + 1LL * B * p.y;\n}\n\nstatic inline ll norm2(pair<int,int> p) {\n    return 1LL * p.first * p.first + 1LL * p.second * p.second;\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\npair<int,int> normalize_pair(ll A, ll B) {\n    if (A == 0 && B == 0) return {0, 0};\n    ll g = std::gcd(std::llabs(A), std::llabs(B));\n    A /= g;\n    B /= g;\n    if (A < 0 || (A == 0 && B < 0)) {\n        A = -A;\n        B = -B;\n    }\n    return {(int)A, (int)B};\n}\n\npair<int,int> random_primitive_large() {\n    while (true) {\n        ll A = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        ll B = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        if (A == 0 && B == 0) continue;\n        auto p = normalize_pair(A, B);\n        if (norm2(p) < 1LL * MIN_NORM * MIN_NORM) continue;\n        return p;\n    }\n}\n\npair<int,int> rotate60(pair<int,int> p) {\n    long double x = 0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first + 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\npair<int,int> rotate120(pair<int,int> p) {\n    long double x = -0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first - 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\nbool better_metrics(int raw1, int mass1, int small1,\n                    int raw2, int mass2, int small2) {\n    if (raw1 != raw2) return raw1 > raw2;\n    if (mass1 != mass2) return mass1 > mass2;\n    return small1 > small2;\n}\n\nbool same_metrics(int raw1, int mass1, int small1,\n                  int raw2, int mass2, int small2) {\n    return raw1 == raw2 && mass1 == mass2 && small1 == small2;\n}\n\nint compute_raw_from_hist(const array<int,11>& hist) {\n    int raw = 0;\n    for (int d = 1; d <= 10; d++) raw += min(a_need[d], hist[d]);\n    return raw;\n}\n\nvoid recompute_score(State& st) {\n    st.hist.fill(0);\n    st.smallCount = 0;\n    st.mass10 = 0;\n    for (int s : st.cellSize) {\n        if (1 <= s && s <= 10) {\n            st.hist[s]++;\n            st.smallCount++;\n        }\n        st.mass10 += min(s, 10);\n    }\n    st.rawScore = compute_raw_from_hist(st.hist);\n}\n\nint index_from_proj(ll u, ll start, ll step, int t) {\n    ll d = u - start;\n    if (d < 0) return 0;\n    ll q = d / step;\n    if (q >= t) return t;\n    if (d % step == 0) return -1; // on a cut line\n    return (int)q + 1;\n}\n\nint raw_from_counts(const vector<int>& cnt) {\n    array<int,11> hist{};\n    for (int c : cnt) if (1 <= c && c <= 10) hist[c]++;\n    return compute_raw_from_hist(hist);\n}\n\nint eval_cand2(const Cand2& c) {\n    static vector<int> cnt;\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    int A1 = c.A, B1 = c.B;\n    auto n2 = normalize_pair(-c.B, c.A);\n    int A2 = n2.first, B2 = n2.second;\n\n    int W = c.t2 + 1;\n    int SZ = (c.t1 + 1) * (c.t2 + 1);\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int i = index_from_proj(proj(A1, B1, p), start1, step1, c.t1);\n        if (i < 0) continue;\n        int j = index_from_proj(proj(A2, B2, p), start2, step2, c.t2);\n        if (j < 0) continue;\n        cnt[i * W + j]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nint eval_cand3(const Cand3& c) {\n    static vector<int> cnt;\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    int W1 = c.t[1] + 1;\n    int W2 = c.t[2] + 1;\n    int SZ = (c.t[0] + 1) * W1 * W2;\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int idx[3];\n        bool bad = false;\n        for (int k = 0; k < 3; k++) {\n            idx[k] = index_from_proj(proj(c.n[k].first, c.n[k].second, p), start[k], step[k], c.t[k]);\n            if (idx[k] < 0) {\n                bad = true;\n                break;\n            }\n        }\n        if (bad) continue;\n        int id = (idx[0] * W1 + idx[1]) * W2 + idx[2];\n        cnt[id]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nbool has_collision_line(int A, int B, ll C) {\n    for (const auto& p : pts) {\n        if (proj(A, B, p) == C) return true;\n    }\n    return false;\n}\n\nll find_valid_C_near(int A, int B, ll base, unordered_set<ll>& used) {\n    auto bad = [&](ll C)->bool {\n        if (used.find(C) != used.end()) return true;\n        return has_collision_line(A, B, C);\n    };\n    if (!bad(base)) return base;\n    for (ll d = 1;; d++) {\n        if (!bad(base + d)) return base + d;\n        if (!bad(base - d)) return base - d;\n    }\n}\n\nvector<Line> build_lines2(const Cand2& c) {\n    auto n1 = normalize_pair(c.A, c.B);\n    auto n2 = normalize_pair(-c.B, c.A);\n\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    vector<Line> res;\n    res.reserve(c.t1 + c.t2);\n\n    unordered_set<ll> used1, used2;\n    used1.reserve(c.t1 * 2 + 3);\n    used2.reserve(c.t2 * 2 + 3);\n\n    for (int j = 0; j < c.t1; j++) {\n        ll C = start1 + 1LL * j * step1;\n        C = find_valid_C_near(n1.first, n1.second, C, used1);\n        used1.insert(C);\n        res.push_back(Line{n1.first, n1.second, C});\n    }\n    for (int j = 0; j < c.t2; j++) {\n        ll C = start2 + 1LL * j * step2;\n        C = find_valid_C_near(n2.first, n2.second, C, used2);\n        used2.insert(C);\n        res.push_back(Line{n2.first, n2.second, C});\n    }\n    return res;\n}\n\nvector<Line> build_lines3(const Cand3& c) {\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    vector<Line> res;\n    res.reserve(c.t[0] + c.t[1] + c.t[2]);\n\n    unordered_set<ll> used[3];\n    for (int k = 0; k < 3; k++) used[k].reserve(c.t[k] * 2 + 3);\n\n    for (int k = 0; k < 3; k++) {\n        auto n = normalize_pair(c.n[k].first, c.n[k].second);\n        for (int j = 0; j < c.t[k]; j++) {\n            ll C = start[k] + 1LL * j * step[k];\n            C = find_valid_C_near(n.first, n.second, C, used[k]);\n            used[k].insert(C);\n            res.push_back(Line{n.first, n.second, C});\n        }\n    }\n    return res;\n}\n\nvoid apply_line(State& st, const Line& ln) {\n    int M = (int)st.cellSize.size();\n\n    static vector<int> pos, neg, newPosId, newNegId;\n    static vector<unsigned char> side;\n\n    pos.assign(M, 0);\n    neg.assign(M, 0);\n    side.assign(N, 0);\n\n    for (int i = 0; i < N; i++) {\n        ll v = proj(ln.A, ln.B, pts[i]) - ln.C;\n        int id = st.cell[i];\n        if (v > 0) {\n            side[i] = 1;\n            pos[id]++;\n        } else {\n            side[i] = 0;\n            neg[id]++;\n        }\n    }\n\n    newPosId.assign(M, -1);\n    newNegId.assign(M, -1);\n    vector<int> newSizes;\n    newSizes.reserve(min(N, 2 * M));\n\n    for (int id = 0; id < M; id++) {\n        if (neg[id] > 0) {\n            newNegId[id] = (int)newSizes.size();\n            newSizes.push_back(neg[id]);\n        }\n        if (pos[id] > 0) {\n            newPosId[id] = (int)newSizes.size();\n            newSizes.push_back(pos[id]);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        int old = st.cell[i];\n        st.cell[i] = side[i] ? newPosId[old] : newNegId[old];\n    }\n    st.cellSize.swap(newSizes);\n    recompute_score(st);\n}\n\nState build_state_excluding(const vector<Line>& lines, int skip = -1) {\n    State st;\n    st.cell.assign(N, 0);\n    st.cellSize = {N};\n    recompute_score(st);\n    for (int i = 0; i < (int)lines.size(); i++) {\n        if (i == skip) continue;\n        apply_line(st, lines[i]);\n    }\n    return st;\n}\n\nState build_state(const vector<Line>& lines) {\n    return build_state_excluding(lines, -1);\n}\n\ndouble estimate_lambda_star() {\n    double bestLam = max(1.0, (double)N / attendees_sum);\n    double bestVal = -1e100;\n    for (double lam = 0.8; lam <= 10.0; lam += 0.02) {\n        double C = N / lam;\n        double p = exp(-lam);\n        double cur = 0.0;\n        double pk = p;\n        for (int d = 1; d <= 10; d++) {\n            pk *= lam / d;\n            cur += min<double>(a_need[d], C * pk);\n        }\n        if (cur > bestVal) {\n            bestVal = cur;\n            bestLam = lam;\n        }\n    }\n    return bestLam;\n}\n\nCand2 random_cand2(double lambdaCenter) {\n    Cand2 c;\n    auto n = random_primitive_large();\n    c.A = n.first;\n    c.B = n.second;\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.85, 0.85)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double aspect = exp(rng.uniform(-0.8, 0.8));\n    double prod = 4.0 * Ctarget / acos(-1.0);\n\n    c.t1 = max(1, (int)llround(sqrt(prod * aspect) - 1.0));\n    c.t2 = max(1, (int)llround(sqrt(prod / aspect) - 1.0));\n\n    int sum = c.t1 + c.t2;\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        c.t1 = max(1, (int)floor(c.t1 * sc));\n        c.t2 = max(1, (int)floor(c.t2 * sc));\n        while (c.t1 + c.t2 > MAX_CUTS) {\n            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n            else if (c.t2 > 1) c.t2--;\n            else break;\n        }\n    }\n\n    c.alpha1 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.alpha2 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.off1 = rng.uniform(-0.5, 0.5);\n    c.off2 = rng.uniform(-0.5, 0.5);\n    return c;\n}\n\nCand3 random_cand3(double lambdaCenter) {\n    Cand3 c;\n    while (true) {\n        auto n0 = random_primitive_large();\n        auto n1 = rotate60(n0);\n        auto n2 = rotate120(n0);\n        if ((n1.first || n1.second) && (n2.first || n2.second)\n            && norm2(n1) >= 250000 && norm2(n2) >= 250000) {\n            c.n[0] = n0;\n            c.n[1] = n1;\n            c.n[2] = n2;\n            break;\n        }\n    }\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.8, 0.8)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double base = sqrt(max(1.0, Ctarget / 3.0));\n\n    for (int k = 0; k < 3; k++) {\n        c.t[k] = max(1, (int)llround(base * exp(rng.uniform(-0.45, 0.45))));\n    }\n\n    int sum = c.t[0] + c.t[1] + c.t[2];\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        for (int k = 0; k < 3; k++) c.t[k] = max(1, (int)floor(c.t[k] * sc));\n        while (c.t[0] + c.t[1] + c.t[2] > MAX_CUTS) {\n            int id = 0;\n            if (c.t[1] > c.t[id]) id = 1;\n            if (c.t[2] > c.t[id]) id = 2;\n            if (c.t[id] > 1) c.t[id]--;\n            else break;\n        }\n    }\n\n    for (int k = 0; k < 3; k++) {\n        c.alpha[k] = clampv(exp(rng.uniform(-0.35, 0.35)), 0.55, 1.6);\n        c.off[k] = rng.uniform(-0.5, 0.5);\n    }\n    return c;\n}\n\nvector<pair<int,int>> unique_normals(const vector<Line>& lines) {\n    set<pair<int,int>> s;\n    for (const auto& ln : lines) s.insert(normalize_pair(ln.A, ln.B));\n    return vector<pair<int,int>>(s.begin(), s.end());\n}\n\npair<int,int> combine_normals(pair<int,int> a, pair<int,int> b, int sign) {\n    ll A = (ll)a.first + sign * (ll)b.first;\n    ll B = (ll)a.second + sign * (ll)b.second;\n    auto p = normalize_pair(A, B);\n    if (p.first == 0 && p.second == 0) return random_primitive_large();\n    return p;\n}\n\nuint64_t norm_key(pair<int,int> p) {\n    uint64_t a = (uint32_t)(p.first + 1000000000);\n    uint64_t b = (uint32_t)(p.second + 1000000000);\n    return (a << 32) ^ b;\n}\n\nvoid add_normal(vector<pair<int,int>>& out, unordered_set<uint64_t>& seen, pair<int,int> n) {\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return;\n    uint64_t key = norm_key(n);\n    if (seen.insert(key).second) out.push_back(n);\n}\n\nvoid dedup_normals(vector<pair<int,int>>& v) {\n    vector<pair<int,int>> out;\n    unordered_set<uint64_t> seen;\n    seen.reserve(v.size() * 2 + 3);\n    for (auto n : v) add_normal(out, seen, n);\n    v.swap(out);\n}\n\nint pick_biased_point(const State& st) {\n    int best = rng.next_int(0, N - 1);\n    for (int t = 0; t < 2; t++) {\n        int x = rng.next_int(0, N - 1);\n        if (st.cellSize[st.cell[x]] > st.cellSize[st.cell[best]]) best = x;\n    }\n    return best;\n}\n\nvector<pair<int,int>> make_candidate_normals(const State& st, const vector<Line>& lines, int want) {\n    vector<pair<int,int>> out;\n    unordered_set<uint64_t> seen;\n    seen.reserve(want * 4 + 32);\n\n    vector<pair<int,int>> fixed = {\n        {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {3,1}, {1,3}, {2,3}, {3,2}\n    };\n    for (auto n : fixed) add_normal(out, seen, n);\n\n    auto base = unique_normals(lines);\n    shuffle(base.begin(), base.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int i = 0; i < (int)base.size() && (int)out.size() < want; i++) {\n        add_normal(out, seen, base[i]);\n        if ((int)out.size() >= want) break;\n        add_normal(out, seen, normalize_pair(-base[i].second, base[i].first));\n    }\n\n    int m = min(6, (int)base.size());\n    for (int i = 0; i < m && (int)out.size() < want; i++) {\n        for (int j = i + 1; j < m && (int)out.size() < want; j++) {\n            add_normal(out, seen, combine_normals(base[i], base[j], +1));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, combine_normals(base[i], base[j], -1));\n        }\n    }\n\n    // centroid directions of largest cells\n    {\n        int M = (int)st.cellSize.size();\n        vector<pair<int,int>> top;\n        top.reserve(M);\n        for (int id = 0; id < M; id++) top.push_back({st.cellSize[id], id});\n        sort(top.begin(), top.end(), [&](auto& l, auto& r){ return l.first > r.first; });\n\n        int take = min(4, (int)top.size());\n        vector<int> ids(take);\n        for (int i = 0; i < take; i++) ids[i] = top[i].second;\n\n        vector<ll> sx(take, 0), sy(take, 0);\n        for (int i = 0; i < N; i++) {\n            int c = st.cell[i];\n            for (int j = 0; j < take; j++) {\n                if (ids[j] == c) {\n                    sx[j] += pts[i].x;\n                    sy[j] += pts[i].y;\n                    break;\n                }\n            }\n        }\n\n        for (int i = 0; i < take && (int)out.size() < want; i++) {\n            for (int j = i + 1; j < take && (int)out.size() < want; j++) {\n                ll dx = sx[j] * st.cellSize[ids[i]] - sx[i] * st.cellSize[ids[j]];\n                ll dy = sy[j] * st.cellSize[ids[i]] - sy[i] * st.cellSize[ids[j]];\n                add_normal(out, seen, normalize_pair(dx, dy));\n                if ((int)out.size() >= want) break;\n                add_normal(out, seen, normalize_pair(-dy, dx));\n            }\n        }\n    }\n\n    // pairs from same large cell\n    for (int t = 0; t < 6 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int ci = st.cell[i];\n        int j = -1;\n        for (int rep = 0; rep < 14; rep++) {\n            int x = rng.next_int(0, N - 1);\n            if (x != i && st.cell[x] == ci) {\n                j = x;\n                break;\n            }\n        }\n        if (j != -1) {\n            int dx = pts[j].x - pts[i].x;\n            int dy = pts[j].y - pts[i].y;\n            add_normal(out, seen, normalize_pair(dx, dy));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, normalize_pair(-dy, dx));\n        }\n    }\n\n    // arbitrary biased pairs\n    for (int t = 0; t < 8 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int j = pick_biased_point(st);\n        if (i == j) continue;\n        int dx = pts[j].x - pts[i].x;\n        int dy = pts[j].y - pts[i].y;\n        add_normal(out, seen, normalize_pair(dx, dy));\n        if ((int)out.size() >= want) break;\n        add_normal(out, seen, normalize_pair(-dy, dx));\n    }\n\n    while ((int)out.size() < want) add_normal(out, seen, random_primitive_large());\n    return out;\n}\n\nBestLineRes best_line_for_normal(const State& st, pair<int,int> n) {\n    BestLineRes res;\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return res;\n\n    static vector<pair<ll,int>> ord;\n    static vector<int> negCnt, tmpCnt, touched;\n\n    ord.resize(N);\n    for (int i = 0; i < N; i++) ord[i] = {proj(n.first, n.second, pts[i]), i};\n    sort(ord.begin(), ord.end());\n\n    int M = (int)st.cellSize.size();\n    negCnt.assign(M, 0);\n    tmpCnt.assign(M, 0);\n    touched.clear();\n\n    auto hist = st.hist;\n    int small = st.smallCount;\n    int mass10 = st.mass10;\n\n    int bestRaw = st.rawScore;\n    int bestMass = st.mass10;\n    int bestSmall = st.smallCount;\n    ll bestC = 0;\n    bool found = false;\n\n    int i = 0;\n    while (i < N) {\n        ll u = ord[i].first;\n        touched.clear();\n        int j = i;\n        while (j < N && ord[j].first == u) {\n            int id = st.cell[ord[j].second];\n            if (tmpCnt[id] == 0) touched.push_back(id);\n            tmpCnt[id]++;\n            j++;\n        }\n\n        for (int id : touched) {\n            int r = tmpCnt[id];\n            tmpCnt[id] = 0;\n\n            int s = st.cellSize[id];\n            int k = negCnt[id];\n            int p = s - k;\n\n            if (1 <= k && k <= 10) hist[k]--;\n            if (1 <= p && p <= 10) hist[p]--;\n\n            small -= (1 <= k && k <= 10);\n            small -= (1 <= p && p <= 10);\n            mass10 -= min(k, 10);\n            mass10 -= min(p, 10);\n\n            int k2 = k + r;\n            int p2 = s - k2;\n            negCnt[id] = k2;\n\n            if (1 <= k2 && k2 <= 10) hist[k2]++;\n            if (1 <= p2 && p2 <= 10) hist[p2]++;\n\n            small += (1 <= k2 && k2 <= 10);\n            small += (1 <= p2 && p2 <= 10);\n            mass10 += min(k2, 10);\n            mass10 += min(p2, 10);\n        }\n\n        if (j < N && ord[j].first > u + 1) {\n            int raw = compute_raw_from_hist(hist);\n            if (better_metrics(raw, mass10, small, bestRaw, bestMass, bestSmall)) {\n                bestRaw = raw;\n                bestMass = mass10;\n                bestSmall = small;\n                bestC = u + 1;\n                found = true;\n            }\n        }\n        i = j;\n    }\n\n    if (!found) return res;\n    res.ok = true;\n    res.raw = bestRaw;\n    res.mass10 = bestMass;\n    res.small = bestSmall;\n    res.line = Line{n.first, n.second, bestC};\n    return res;\n}\n\nbool better_init_sol(const State& s1, int l1, const State& s2, int l2) {\n    if (s1.rawScore != s2.rawScore) return s1.rawScore > s2.rawScore;\n    if (s1.mass10 != s2.mass10) return s1.mass10 > s2.mass10;\n    if (s1.smallCount != s2.smallCount) return s1.smallCount > s2.smallCount;\n    return l1 < l2;\n}\n\nbool try_add_one_exact(State& cur, vector<Line>& curLines, int wantNormals, bool allowSetup) {\n    if ((int)curLines.size() >= K) return false;\n\n    auto cands = make_candidate_normals(cur, curLines, wantNormals);\n\n    BestLineRes best;\n    best.raw = cur.rawScore;\n    best.mass10 = cur.mass10;\n    best.small = cur.smallCount;\n\n    for (auto n : cands) {\n        auto r = best_line_for_normal(cur, n);\n        if (!r.ok) continue;\n        if (better_metrics(r.raw, r.mass10, r.small, best.raw, best.mass10, best.small)) {\n            best = r;\n        }\n    }\n\n    if (best.ok && best.raw > cur.rawScore) {\n        apply_line(cur, best.line);\n        curLines.push_back(best.line);\n        return true;\n    }\n\n    // very conservative setup move\n    if (allowSetup && best.ok &&\n        best.raw == cur.rawScore &&\n        best.mass10 >= cur.mass10 + 9 &&\n        (int)curLines.size() + 8 < K) {\n        apply_line(cur, best.line);\n        curLines.push_back(best.line);\n        return true;\n    }\n\n    return false;\n}\n\nbool prune_once(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n    vector<int> order(curLines.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int idp = 0; idp < (int)order.size(); idp++) {\n        if (timer.elapsed() >= endTime) break;\n        int idx = order[idp];\n        State base = build_state_excluding(curLines, idx);\n\n        if (better_metrics(base.rawScore, base.mass10, base.smallCount,\n                           cur.rawScore, cur.mass10, cur.smallCount) ||\n            same_metrics(base.rawScore, base.mass10, base.smallCount,\n                         cur.rawScore, cur.mass10, cur.smallCount)) {\n            cur = std::move(base);\n            curLines.erase(curLines.begin() + idx);\n            return true;\n        }\n    }\n    return false;\n}\n\nbool retune_pass(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n    bool changed = false;\n\n    vector<int> order(curLines.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int t = 0; t < (int)order.size(); t++) {\n        if (timer.elapsed() >= endTime) break;\n        int idx = order[t];\n        if (idx >= (int)curLines.size()) continue;\n\n        State base = build_state_excluding(curLines, idx);\n        auto n = normalize_pair(curLines[idx].A, curLines[idx].B);\n        auto r = best_line_for_normal(base, n);\n        if (!r.ok) continue;\n\n        if (better_metrics(r.raw, r.mass10, r.small,\n                           cur.rawScore, cur.mass10, cur.smallCount)) {\n            curLines[idx] = r.line;\n            cur = std::move(base);\n            apply_line(cur, r.line);\n            changed = true;\n        }\n    }\n    return changed;\n}\n\nbool replace_once(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n\n    int L = (int)curLines.size();\n    vector<int> candIdx;\n    vector<char> used(L, 0);\n\n    for (int i = max(0, L - 6); i < L; i++) {\n        used[i] = 1;\n        candIdx.push_back(i);\n    }\n    while ((int)candIdx.size() < min(L, 10)) {\n        int x = rng.next_int(0, L - 1);\n        if (!used[x]) {\n            used[x] = 1;\n            candIdx.push_back(x);\n        }\n    }\n\n    int bestIdx = -1;\n    State bestBase;\n    BestLineRes bestMove;\n    bestMove.raw = cur.rawScore;\n    bestMove.mass10 = cur.mass10;\n    bestMove.small = cur.smallCount;\n\n    for (int idx : candIdx) {\n        if (timer.elapsed() >= endTime) break;\n\n        State base = build_state_excluding(curLines, idx);\n\n        // pruning opportunity\n        if (better_metrics(base.rawScore, base.mass10, base.smallCount,\n                           cur.rawScore, cur.mass10, cur.smallCount)) {\n            cur = std::move(base);\n            curLines.erase(curLines.begin() + idx);\n            return true;\n        }\n\n        vector<Line> tempLines;\n        tempLines.reserve(L - 1);\n        for (int i = 0; i < L; i++) if (i != idx) tempLines.push_back(curLines[i]);\n\n        auto cands = make_candidate_normals(base, tempLines, 14);\n        auto oldn = normalize_pair(curLines[idx].A, curLines[idx].B);\n        cands.push_back(oldn);\n        cands.push_back(normalize_pair(-oldn.second, oldn.first));\n        dedup_normals(cands);\n\n        for (auto n : cands) {\n            if (timer.elapsed() >= endTime) break;\n            auto r = best_line_for_normal(base, n);\n            if (!r.ok) continue;\n            if (better_metrics(r.raw, r.mass10, r.small,\n                               bestMove.raw, bestMove.mass10, bestMove.small)) {\n                bestMove = r;\n                bestIdx = idx;\n                bestBase = base;\n            }\n        }\n    }\n\n    if (bestIdx != -1 &&\n        better_metrics(bestMove.raw, bestMove.mass10, bestMove.small,\n                       cur.rawScore, cur.mass10, cur.smallCount)) {\n        curLines[bestIdx] = bestMove.line;\n        cur = std::move(bestBase);\n        apply_line(cur, bestMove.line);\n        return true;\n    }\n    return false;\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = (a >= 0 ? 1 : -1);\n        y = 0;\n        return std::llabs(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\nll modinv(ll a, ll mod) {\n    if (mod == 1) return 0;\n    ll x, y;\n    ll g = extgcd(a, mod, x, y);\n    if (g != 1) return 0;\n    x %= mod;\n    if (x < 0) x += mod;\n    return x;\n}\n\narray<ll,4> line_to_points(const Line& ln) {\n    const ll LIM = 1000000000LL - 5;\n    ll A = ln.A, B = ln.B, C = ln.C;\n\n    if (B == 0) {\n        ll x = C / A;\n        return {x, -LIM, x, LIM};\n    }\n    if (A == 0) {\n        ll y = C / B;\n        return {-LIM, y, LIM, y};\n    }\n\n    ll b = std::llabs(B);\n    ll a = ((A % b) + b) % b;\n    ll c = ((C % b) + b) % b;\n    ll inv = modinv(a, b);\n    ll x0 = (ll)((__int128)inv * c % b);\n    ll y0 = (C - A * x0) / B;\n\n    ll t1 = (LIM - std::llabs(x0)) / std::llabs(B);\n    ll t2 = (LIM - std::llabs(y0)) / std::llabs(A);\n    ll t = min(t1, t2);\n    t = min<ll>(t, 200000);\n    if (t < 1) t = 1;\n\n    ll x1 = x0 - B * t;\n    ll y1 = y0 + A * t;\n    ll x2 = x0 + B * t;\n    ll y2 = y0 - A * t;\n\n    while ((std::llabs(x1) > LIM || std::llabs(y1) > LIM ||\n            std::llabs(x2) > LIM || std::llabs(y2) > LIM) && t > 1) {\n        t /= 2;\n        x1 = x0 - B * t;\n        y1 = y0 + A * t;\n        x2 = x0 + B * t;\n        y2 = y0 - A * t;\n    }\n    return {x1, y1, x2, y2};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    uint64_t seed = 0x123456789abcdef0ull;\n\n    seed ^= splitmix64((uint64_t)N);\n    seed ^= splitmix64((uint64_t)K);\n\n    for (int d = 1; d <= 10; d++) {\n        cin >> a_need[d];\n        attendees_sum += a_need[d];\n        seed ^= splitmix64((uint64_t)(a_need[d] + 1000 * d + 1));\n    }\n\n    pts.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> pts[i].x >> pts[i].y;\n        uint64_t v1 = (uint64_t)(pts[i].x + 20000);\n        uint64_t v2 = (uint64_t)(pts[i].y + 20000);\n        seed ^= splitmix64((v1 << 21) ^ v2 ^ (uint64_t)i * 0x9e3779b97f4a7c15ull);\n    }\n    rng = XorShift64(splitmix64(seed));\n\n    Timer timer;\n\n    const double INITIAL_END = 0.82;\n    const double AUG1_END    = 1.55;\n    const double MID_END     = 2.35;\n    const double REPL_END    = 2.88;\n    const double FINAL_END   = 2.96;\n\n    double lambdaStar = estimate_lambda_star();\n    double lambdaAvg = max(1.0, (double)N / attendees_sum);\n\n    vector<Line> bestLines;\n    State bestState = build_state({});\n    bestLines.clear();\n\n    // deterministic-ish 2-bundle seeds\n    {\n        vector<pair<int,int>> seedNormals = {\n            {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {3,1}, {1,3}\n        };\n        vector<double> lams = {\n            clampv(lambdaStar * 0.85, 1.0, 12.0),\n            clampv(lambdaStar,        1.0, 12.0),\n            clampv(lambdaStar * 1.15, 1.0, 12.0),\n            clampv(lambdaAvg,         1.0, 12.0),\n        };\n        vector<double> alphas = {0.90, 1.00, 1.10};\n        vector<double> offs = {0.0, 0.25};\n\n        for (auto n0 : seedNormals) {\n            auto n = normalize_pair(n0.first, n0.second);\n            for (double lam : lams) {\n                for (double alpha : alphas) {\n                    for (double off : offs) {\n                        Cand2 c;\n                        c.A = n.first;\n                        c.B = n.second;\n                        double Ctarget = N / lam;\n                        double prod = 4.0 * Ctarget / acos(-1.0);\n                        c.t1 = c.t2 = max(1, (int)llround(sqrt(prod) - 1.0));\n                        while (c.t1 + c.t2 > MAX_CUTS) {\n                            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n                            else if (c.t2 > 1) c.t2--;\n                            else break;\n                        }\n                        c.alpha1 = c.alpha2 = alpha;\n                        c.off1 = off;\n                        c.off2 = -off;\n\n                        auto lines = build_lines2(c);\n                        State st = build_state(lines);\n                        if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                            bestState = st;\n                            bestLines = lines;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // random bundled search\n    while (timer.elapsed() < INITIAL_END) {\n        bool use3 = (rng.next() % 10 < 3);\n        if (!use3) {\n            Cand2 c = random_cand2(lambdaStar);\n            int approx = eval_cand2(c);\n            if (approx + 2 >= bestState.rawScore) {\n                auto lines = build_lines2(c);\n                State st = build_state(lines);\n                if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                    bestState = st;\n                    bestLines = lines;\n                }\n            }\n        } else {\n            Cand3 c = random_cand3(lambdaStar);\n            int approx = eval_cand3(c);\n            if (approx + 2 >= bestState.rawScore) {\n                auto lines = build_lines3(c);\n                State st = build_state(lines);\n                if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                    bestState = st;\n                    bestLines = lines;\n                }\n            }\n        }\n    }\n\n    vector<Line> curLines = bestLines;\n    State cur = bestState;\n\n    // phase 1: exact augmentation\n    {\n        int stall = 0;\n        while ((int)curLines.size() < K && timer.elapsed() < AUG1_END && stall < 5 && cur.rawScore < attendees_sum) {\n            int want = (timer.elapsed() < 1.20 ? 28 : 22);\n            bool allowSetup = (stall >= 2);\n            if (try_add_one_exact(cur, curLines, want, allowSetup)) stall = 0;\n            else stall++;\n        }\n    }\n\n    // phase 2: prune + retune coordinate descent\n    while (timer.elapsed() < MID_END) {\n        bool changed = false;\n\n        if (prune_once(cur, curLines, timer, MID_END)) {\n            changed = true;\n            if (timer.elapsed() < MID_END - 0.05 && (int)curLines.size() < K) {\n                try_add_one_exact(cur, curLines, 18, false);\n            }\n            continue;\n        }\n\n        if (retune_pass(cur, curLines, timer, MID_END)) {\n            changed = true;\n        }\n\n        if (!changed) break;\n    }\n\n    // phase 3: replacement neighborhood\n    {\n        int stall = 0;\n        while (timer.elapsed() < REPL_END && stall < 5) {\n            bool changed = replace_once(cur, curLines, timer, REPL_END);\n            if (changed) {\n                stall = 0;\n                if (timer.elapsed() < REPL_END - 0.04 && (int)curLines.size() < K) {\n                    try_add_one_exact(cur, curLines, 16, false);\n                }\n            } else {\n                stall++;\n            }\n        }\n    }\n\n    // final exact augmentation\n    {\n        int stall = 0;\n        while ((int)curLines.size() < K && timer.elapsed() < FINAL_END && stall < 4 && cur.rawScore < attendees_sum) {\n            if (try_add_one_exact(cur, curLines, 18, false)) stall = 0;\n            else stall++;\n        }\n    }\n\n    cout << curLines.size() << '\\n';\n    for (const auto& ln : curLines) {\n        auto p = line_to_points(ln);\n        cout << p[0] << ' ' << p[1] << ' ' << p[2] << ' ' << p[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int MAXID = MAXN * MAXN;\nstatic constexpr int MAXD = 2 * MAXN - 1;\nstatic constexpr double EPS = 1e-12;\n\nint GX[MAXID], GY[MAXID];\ninline int enc(int x, int y) { return y * MAXN + x; }\n\nstruct CoordInit {\n    CoordInit() {\n        for (int y = 0; y < MAXN; ++y) {\n            for (int x = 0; x < MAXN; ++x) {\n                int id = enc(x, y);\n                GX[id] = x;\n                GY[id] = y;\n            }\n        }\n    }\n} coord_init;\n\nstruct Operation {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n};\n\nstruct Candidate {\n    Operation op;\n    double key;\n    int gain;\n    int cost1; // len1 + len2\n    int cost2; // len1^2 + len2^2\n};\n\nstruct Params {\n    double lambda0, lambda1; // linear penalty\n    double quad0, quad1;     // quadratic penalty\n    int topK;\n    int randDepth;\n};\n\nclass Solver {\n    enum Dir {\n        LEFT = 0, RIGHT = 1, DOWN = 2, UP = 3,\n        NE = 4, NW = 5, SW = 6, SE = 7\n    };\n\n    static constexpr int KEEP = 48;\n\n    int N, M, c;\n    int phaseLen;\n\n    vector<int> initialIds;\n    vector<int> cellOrder;\n\n    array<pair<int,int>, 8> pairs{\n        pair<int,int>{LEFT, DOWN},\n        pair<int,int>{LEFT, UP},\n        pair<int,int>{RIGHT, DOWN},\n        pair<int,int>{RIGHT, UP},\n        pair<int,int>{NE, NW},\n        pair<int,int>{NE, SE},\n        pair<int,int>{SW, NW},\n        pair<int,int>{SW, SE}\n    };\n\n    int weight[MAXN][MAXN]{};\n\n    unsigned char dot[MAXN][MAXN]{};\n    unsigned char useH[MAXN - 1][MAXN]{};\n    unsigned char useV[MAXN][MAXN - 1]{};\n    unsigned char useD1[MAXN - 1][MAXN - 1]{};\n    unsigned char useD2[MAXN - 1][MAXN - 1]{};\n\n    int nearDot[8][MAXN][MAXN]{};\n\n    int prefH[MAXN][MAXN + 1]{};\n    int prefV[MAXN][MAXN + 1]{};\n    int prefD1[MAXD][MAXN + 1]{};\n    int prefD2[MAXD][MAXN + 1]{};\n\n    long long initialWeight = 0;\n    long long curWeight = 0;\n    long long bestWeight = 0;\n\n    vector<Operation> ops;\n    vector<Operation> bestOps;\n\n    mt19937_64 rng;\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    static bool betterCand(const Candidate& a, const Candidate& b) {\n        if (a.key > b.key + EPS) return true;\n        if (a.key + EPS < b.key) return false;\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.cost2 != b.cost2) return a.cost2 < b.cost2;\n        if (a.cost1 != b.cost1) return a.cost1 < b.cost1;\n        return false;\n    }\n\n    void consider(vector<Candidate>& top, const Candidate& cand, int keep) {\n        int pos = (int)top.size();\n        while (pos > 0 && betterCand(cand, top[pos - 1])) --pos;\n        if (pos >= keep) return;\n        top.insert(top.begin() + pos, cand);\n        if ((int)top.size() > keep) top.pop_back();\n    }\n\n    int chooseIndex(int lim) {\n        if (lim <= 1) return 0;\n        uint64_t sum = (uint64_t)lim * (lim + 1) / 2;\n        uint64_t r = rng() % sum;\n        uint64_t acc = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (uint64_t)(lim - i);\n            if (r < acc) return i;\n        }\n        return 0;\n    }\n\n    void resetState() {\n        memset(dot, 0, sizeof(dot));\n        memset(useH, 0, sizeof(useH));\n        memset(useV, 0, sizeof(useV));\n        memset(useD1, 0, sizeof(useD1));\n        memset(useD2, 0, sizeof(useD2));\n        for (int id : initialIds) {\n            dot[GX[id]][GY[id]] = 1;\n        }\n        curWeight = initialWeight;\n        ops.clear();\n    }\n\n    void recomputeAux() {\n        // rows\n        for (int y = 0; y < N; ++y) {\n            int last = -1;\n            for (int x = 0; x < N; ++x) {\n                nearDot[LEFT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int x = N - 1; x >= 0; --x) {\n                nearDot[RIGHT][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // columns\n        for (int x = 0; x < N; ++x) {\n            int last = -1;\n            for (int y = 0; y < N; ++y) {\n                nearDot[DOWN][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n            last = -1;\n            for (int y = N - 1; y >= 0; --y) {\n                nearDot[UP][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // main diagonals: x - y = const\n        for (int d = -(N - 1); d <= (N - 1); ++d) {\n            int minx = max(0, d);\n            int maxx = min(N - 1, N - 1 + d);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = x - d;\n                nearDot[SW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = x - d;\n                nearDot[NE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // anti-diagonals: x + y = const\n        for (int s = 0; s <= 2 * (N - 1); ++s) {\n            int minx = max(0, s - (N - 1));\n            int maxx = min(N - 1, s);\n\n            int last = -1;\n            for (int x = minx; x <= maxx; ++x) {\n                int y = s - x;\n                nearDot[NW][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n\n            last = -1;\n            for (int x = maxx; x >= minx; --x) {\n                int y = s - x;\n                nearDot[SE][x][y] = last;\n                if (dot[x][y]) last = enc(x, y);\n            }\n        }\n\n        // prefix sums for used segments\n        for (int y = 0; y < N; ++y) {\n            prefH[y][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int add = (x < N - 1 ? useH[x][y] : 0);\n                prefH[y][x + 1] = prefH[y][x] + add;\n            }\n        }\n\n        for (int x = 0; x < N; ++x) {\n            prefV[x][0] = 0;\n            for (int y = 0; y < N; ++y) {\n                int add = (y < N - 1 ? useV[x][y] : 0);\n                prefV[x][y + 1] = prefV[x][y] + add;\n            }\n        }\n\n        for (int didx = 0; didx < 2 * N - 1; ++didx) {\n            int d = didx - (N - 1);\n            prefD1[didx][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = x - d;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD1[x][y];\n                prefD1[didx][x + 1] = prefD1[didx][x] + add;\n            }\n        }\n\n        for (int s = 0; s < 2 * N - 1; ++s) {\n            prefD2[s][0] = 0;\n            for (int x = 0; x < N; ++x) {\n                int y = s - x - 1;\n                int add = 0;\n                if (x < N - 1 && 0 <= y && y < N - 1) add = useD2[x][y];\n                prefD2[s][x + 1] = prefD2[s][x] + add;\n            }\n        }\n    }\n\n    int usedCountOnSegment(int x1, int y1, int x2, int y2) const {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefH[y1][r] - prefH[y1][l];\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            return prefV[x1][r] - prefV[x1][l];\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + (N - 1);\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD1[d][r] - prefD1[d][l];\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return prefD2[s][r] - prefD2[s][l];\n        }\n    }\n\n    void markSegment(int x1, int y1, int x2, int y2) {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) useH[x][y1] = 1;\n            return;\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            for (int y = l; y < r; ++y) useV[x1][y] = 1;\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = x - d;\n                useD1[x][y] = 1;\n            }\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            for (int x = l; x < r; ++x) {\n                int y = s - x - 1;\n                useD2[x][y] = 1;\n            }\n        }\n    }\n\n    void apply(const Candidate& cand) {\n        const auto& o = cand.op;\n        dot[o.x1][o.y1] = 1;\n        curWeight += weight[o.x1][o.y1];\n\n        markSegment(o.x1, o.y1, o.x2, o.y2);\n        markSegment(o.x2, o.y2, o.x3, o.y3);\n        markSegment(o.x3, o.y3, o.x4, o.y4);\n        markSegment(o.x4, o.y4, o.x1, o.y1);\n\n        ops.push_back(o);\n    }\n\n    double interp(double a, double b, int step) const {\n        if (step >= phaseLen) return b;\n        double t = double(phaseLen - step) / phaseLen;\n        return b + (a - b) * t;\n    }\n\n    vector<Candidate> collectTop(double lambda, double quad, int keep) {\n        vector<Candidate> top;\n        top.reserve(keep);\n\n        for (int id1 : cellOrder) {\n            int x = GX[id1], y = GY[id1];\n            if (dot[x][y]) continue;\n\n            int gain = weight[x][y];\n            if ((int)top.size() == keep) {\n                double upper = gain - lambda * 2.0 - quad * 2.0; // len1=len2=1\n                if (upper + EPS < top.back().key) break;\n            }\n\n            for (auto [da, db] : pairs) {\n                int id2 = nearDot[da][x][y];\n                if (id2 < 0) continue;\n                int id4 = nearDot[db][x][y];\n                if (id4 < 0) continue;\n\n                int x2 = GX[id2], y2 = GY[id2];\n                int x4 = GX[id4], y4 = GY[id4];\n\n                int x3 = x2 + x4 - x;\n                int y3 = y2 + y4 - y;\n                if (!inside(x3, y3)) continue;\n                if (!dot[x3][y3]) continue;\n\n                int id3 = enc(x3, y3);\n\n                // no other dots on perimeter\n                if (nearDot[db][x2][y2] != id3) continue;\n                if (nearDot[da][x4][y4] != id3) continue;\n\n                // no positive-length overlap with already drawn segments\n                if (usedCountOnSegment(x, y, x2, y2)) continue;\n                if (usedCountOnSegment(x2, y2, x3, y3)) continue;\n                if (usedCountOnSegment(x3, y3, x4, y4)) continue;\n                if (usedCountOnSegment(x4, y4, x, y)) continue;\n\n                int len1 = max(abs(x2 - x), abs(y2 - y));\n                int len2 = max(abs(x4 - x), abs(y4 - y));\n                int cost1 = len1 + len2;\n                int cost2 = len1 * len1 + len2 * len2;\n\n                Candidate cand{\n                    Operation{x, y, x2, y2, x3, y3, x4, y4},\n                    gain - lambda * cost1 - quad * cost2,\n                    gain,\n                    cost1,\n                    cost2\n                };\n                consider(top, cand, keep);\n            }\n        }\n\n        return top;\n    }\n\n    void runAttempt(const Params& prm,\n                    chrono::steady_clock::time_point deadline,\n                    const vector<int>& forcedRanks = {}) {\n        resetState();\n        int step = 0;\n\n        while (true) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            recomputeAux();\n            double lambda = interp(prm.lambda0, prm.lambda1, step);\n            double quad = interp(prm.quad0, prm.quad1, step);\n            auto top = collectTop(lambda, quad, KEEP);\n            if (top.empty()) break;\n\n            int idx = 0;\n            if (step < (int)forcedRanks.size()) {\n                idx = min(forcedRanks[step], (int)top.size() - 1);\n            } else if (step < prm.randDepth && prm.topK > 1) {\n                idx = chooseIndex(min(prm.topK, (int)top.size()));\n            }\n\n            apply(top[idx]);\n            ++step;\n        }\n\n        if (curWeight > bestWeight) {\n            bestWeight = curWeight;\n            bestOps = ops;\n        }\n    }\n\n    int rootTopCount(const Params& prm, int cap) {\n        resetState();\n        recomputeAux();\n        auto top = collectTop(interp(prm.lambda0, prm.lambda1, 0),\n                              interp(prm.quad0, prm.quad1, 0),\n                              cap);\n        return (int)top.size();\n    }\n\npublic:\n    Solver(int N_, int M_, const vector<pair<int,int>>& pts) : N(N_), M(M_), c((N_ - 1) / 2) {\n        phaseLen = max(18, min(40, N));\n\n        uint64_t seed = chrono::steady_clock::now().time_since_epoch().count();\n        seed ^= (uint64_t)N * 1000003ULL;\n        seed ^= (uint64_t)M * 10007ULL;\n        for (auto [x, y] : pts) {\n            seed ^= (uint64_t)(x + 1) * 911382323ULL;\n            seed ^= (uint64_t)(y + 7) * 972663749ULL;\n        }\n        rng.seed(seed);\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                weight[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n                cellOrder.push_back(enc(x, y));\n            }\n        }\n\n        stable_sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n            int xa = GX[a], ya = GY[a];\n            int xb = GX[b], yb = GY[b];\n            if (weight[xa][ya] != weight[xb][yb]) return weight[xa][ya] > weight[xb][yb];\n            int ma = max(abs(xa - c), abs(ya - c));\n            int mb = max(abs(xb - c), abs(yb - c));\n            if (ma != mb) return ma > mb;\n            int sa = abs(xa - c) + abs(ya - c);\n            int sb = abs(xb - c) + abs(yb - c);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n\n        for (auto [x, y] : pts) {\n            int id = enc(x, y);\n            initialIds.push_back(id);\n            initialWeight += weight[x][y];\n        }\n\n        curWeight = bestWeight = initialWeight;\n        ops.reserve(N * N);\n        bestOps.reserve(N * N);\n    }\n\n    void solve() {\n        auto start = chrono::steady_clock::now();\n        auto deadline = start + chrono::milliseconds(4700);\n\n        // Fast deterministic baselines (close to the best earlier version)\n        vector<Params> fixed = {\n            {20.0, 20.0, 0.0, 0.0, 1, 0},\n            {12.0, 12.0, 0.0, 0.0, 1, 0},\n            { 8.0,  8.0, 0.0, 0.0, 1, 0},\n            { 4.0,  4.0, 0.0, 0.0, 1, 0},\n            { 2.0,  2.0, 0.0, 0.0, 1, 0},\n            { 1.0,  1.0, 0.0, 0.0, 1, 0},\n            { 0.5,  0.5, 0.0, 0.0, 1, 0},\n            { 0.0,  0.0, 0.0, 0.0, 1, 0},\n\n            {12.0,  2.0, 0.0, 0.0, 1, 0},\n            { 8.0,  1.0, 0.0, 0.0, 1, 0},\n            { 4.0,  0.0, 0.0, 0.0, 1, 0},\n            { 2.0,  0.0, 0.0, 0.0, 1, 0},\n\n            // tiny quadratic penalty in a few attempts only\n            { 8.0,  1.0, 0.10, 0.00, 1, 0},\n            { 4.0,  0.0, 0.15, 0.00, 1, 0},\n\n            { 4.0,  0.0, 0.0, 0.0, 4, 10},\n            { 2.0,  0.0, 0.0, 0.0, 6, 16},\n            { 1.0,  0.0, 0.0, 0.0, 8, 24},\n            { 0.5,  0.0, 0.0, 0.0,10, 32},\n            { 0.0,  0.0, 0.0, 0.0,10, 40}\n        };\n\n        for (const auto& prm : fixed) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            runAttempt(prm, deadline);\n        }\n\n        // Lightweight systematic diversification on first move\n        vector<Params> prefixParams = {\n            {8.0, 1.0, 0.0, 0.0, 1, 0},\n            {4.0, 0.0, 0.0, 0.0, 1, 0},\n            {2.0, 0.0, 0.0, 0.0, 1, 0}\n        };\n\n        for (const auto& prm : prefixParams) {\n            if (chrono::steady_clock::now() + chrono::milliseconds(120) >= deadline) break;\n            int cnt = rootTopCount(prm, 6);\n            for (int r = 0; r < cnt; ++r) {\n                if (chrono::steady_clock::now() + chrono::milliseconds(60) >= deadline) break;\n                runAttempt(prm, deadline, {r});\n            }\n        }\n\n        // Very small two-move prefix exploration\n        {\n            Params prm{4.0, 0.0, 0.0, 0.0, 1, 0};\n            if (chrono::steady_clock::now() + chrono::milliseconds(160) < deadline) {\n                for (int r1 = 0; r1 < 3; ++r1) {\n                    for (int r2 = 0; r2 < 2; ++r2) {\n                        if (chrono::steady_clock::now() + chrono::milliseconds(60) >= deadline) break;\n                        runAttempt(prm, deadline, {r1, r2});\n                    }\n                }\n            }\n        }\n\n        static const vector<double> L0 = {0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 12.0, 16.0, 20.0};\n        static const vector<double> L1 = {0.0, 0.0, 0.25, 0.5, 1.0, 2.0};\n        static const vector<double> Q0 = {0.0, 0.0, 0.0, 0.05, 0.10, 0.15, 0.20};\n        static const vector<int> TK = {1, 2, 3, 4, 6, 8, 10, 12};\n        static const vector<int> RD = {0, 4, 8, 12, 16, 24, 32, 48, 64};\n\n        while (chrono::steady_clock::now() < deadline) {\n            Params prm;\n            prm.lambda0 = L0[(size_t)(rng() % L0.size())];\n            prm.lambda1 = L1[(size_t)(rng() % L1.size())];\n            if (prm.lambda1 > prm.lambda0) swap(prm.lambda0, prm.lambda1);\n\n            prm.quad0 = Q0[(size_t)(rng() % Q0.size())];\n            prm.quad1 = 0.0;\n            if ((rng() & 3ULL) == 0) prm.quad0 = 0.0; // often pure baseline\n\n            prm.topK = TK[(size_t)(rng() % TK.size())];\n            prm.randDepth = RD[(size_t)(rng() % RD.size())];\n            if (prm.topK == 1) prm.randDepth = 0;\n\n            uint64_t mode = rng() & 31ULL;\n            if (mode == 0) {\n                runAttempt(prm, deadline, {(int)(rng() % 6)});\n            } else if (mode == 1) {\n                runAttempt(prm, deadline, {(int)(rng() % 4), (int)(rng() % 3)});\n            } else {\n                runAttempt(prm, deadline);\n            }\n        }\n    }\n\n    void output() const {\n        cout << bestOps.size() << '\\n';\n        for (const auto& o : bestOps) {\n            cout << o.x1 << ' ' << o.y1 << ' '\n                 << o.x2 << ' ' << o.y2 << ' '\n                 << o.x3 << ' ' << o.y3 << ' '\n                 << o.x4 << ' ' << o.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<pair<int,int>> pts(M);\n    for (int i = 0; i < M; ++i) {\n        cin >> pts[i].first >> pts[i].second;\n    }\n\n    Solver solver(N, M, pts);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Board {\n    array<uint8_t, 100> a;\n};\n\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'}; // F=up, B=down, L=left, R=right\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nclass Solver {\n    static constexpr double TIME_LIMIT = 1.80;\n\n    int flavor[101]{};\n    int totalCnt[4]{};\n    int suffixCnt[103][4]{};\n\n    Board cur{};\n    SplitMix64 rng;\n    chrono::steady_clock::time_point st;\n\n    int perms[6][3] = {\n        {1,2,3}, {1,3,2}, {2,1,3},\n        {2,3,1}, {3,1,2}, {3,2,1}\n    };\n\n    uint8_t pathCell[8][100]{};\n    uint8_t distCost[48][100][4]{}; // [pattern][cell][color]\n    int lastPattern = -1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    static inline void place_by_rank(Board &b, int rank, int f) {\n        for (int i = 0; i < 100; ++i) {\n            if (b.a[i] == 0) {\n                if (--rank == 0) {\n                    b.a[i] = (uint8_t)f;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline int collect_empties(const Board &b, int out[100]) {\n        int m = 0;\n        for (int i = 0; i < 100; ++i) if (b.a[i] == 0) out[m++] = i;\n        return m;\n    }\n\n    static inline void apply_tilt(const Board &src, int dir, Board &dst) {\n        dst.a.fill(0);\n        if (dir == 0) { // F\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 0;\n                for (int r = 0; r < 10; ++r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[(ptr++) * 10 + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 9;\n                for (int r = 9; r >= 0; --r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[(ptr--) * 10 + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 0;\n                for (int c = 0; c < 10; ++c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + (ptr++)] = v;\n                }\n            }\n        } else { // R\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 9;\n                for (int c = 9; c >= 0; --c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + (ptr--)] = v;\n                }\n            }\n        }\n    }\n\n    static int comp_sq_only(const Board &b) {\n        uint8_t vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    void init_patterns() {\n        int pid = 0;\n\n        // 4 row snakes\n        for (int fv = 0; fv < 2; ++fv) {\n            for (int fh = 0; fh < 2; ++fh) {\n                int k = 0;\n                for (int r = 0; r < 10; ++r) {\n                    if ((r & 1) == 0) {\n                        for (int c = 0; c < 10; ++c) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    } else {\n                        for (int c = 9; c >= 0; --c) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    }\n                }\n                ++pid;\n            }\n        }\n\n        // 4 col snakes\n        for (int fv = 0; fv < 2; ++fv) {\n            for (int fh = 0; fh < 2; ++fh) {\n                int k = 0;\n                for (int c = 0; c < 10; ++c) {\n                    if ((c & 1) == 0) {\n                        for (int r = 0; r < 10; ++r) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    } else {\n                        for (int r = 9; r >= 0; --r) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    }\n                }\n                ++pid;\n            }\n        }\n\n        for (int p = 0; p < 8; ++p) {\n            for (int q = 0; q < 6; ++q) {\n                int pat = p * 6 + q;\n                int L[4] = {}, R[4] = {};\n                int curPos = 0;\n                for (int t = 0; t < 3; ++t) {\n                    int c = perms[q][t];\n                    if (totalCnt[c] == 0) {\n                        L[c] = 0;\n                        R[c] = -1;\n                    } else {\n                        L[c] = curPos;\n                        R[c] = curPos + totalCnt[c] - 1;\n                        curPos += totalCnt[c];\n                    }\n                }\n\n                for (int idx = 0; idx < 100; ++idx) {\n                    int cell = pathCell[p][idx];\n                    for (int c = 1; c <= 3; ++c) {\n                        int dist = 0;\n                        if (totalCnt[c] == 0) dist = 0;\n                        else if (idx < L[c]) dist = L[c] - idx;\n                        else if (idx > R[c]) dist = idx - R[c];\n                        else dist = 0;\n                        distCost[pat][cell][c] = (uint8_t)dist;\n                    }\n                }\n            }\n        }\n    }\n\n    inline int pattern_penalty(const Board &b, int pat) const {\n        int sum = 0;\n        for (int i = 0; i < 100; ++i) {\n            uint8_t col = b.a[i];\n            if (col) sum += distCost[pat][i][col];\n        }\n        return sum;\n    }\n\n    int best_pattern_for_board(const Board &b) const {\n        int bestPat = 0;\n        int bestScore = INT_MAX;\n        for (int pat = 0; pat < 48; ++pat) {\n            int s = pattern_penalty(b, pat);\n            if (s < bestScore) {\n                bestScore = s;\n                bestPat = pat;\n            }\n        }\n        return bestPat;\n    }\n\n    int select_active_patterns(const Board cand[4], int active[3]) const {\n        int bestPat = -1, bestScore = INT_MAX;\n        int secondPat = -1, secondScore = INT_MAX;\n        int thirdPat = -1, thirdScore = INT_MAX;\n        int lastScore = INT_MAX;\n\n        for (int pat = 0; pat < 48; ++pat) {\n            int s = 0;\n            for (int d = 0; d < 4; ++d) s += pattern_penalty(cand[d], pat);\n            if (pat == lastPattern) lastScore = s;\n\n            if (s < bestScore) {\n                thirdScore = secondScore; thirdPat = secondPat;\n                secondScore = bestScore; secondPat = bestPat;\n                bestScore = s; bestPat = pat;\n            } else if (s < secondScore) {\n                thirdScore = secondScore; thirdPat = secondPat;\n                secondScore = s; secondPat = pat;\n            } else if (s < thirdScore) {\n                thirdScore = s; thirdPat = pat;\n            }\n        }\n\n        int n = 0;\n        bool keepLast = (lastPattern != -1 && lastPattern != bestPat && lastScore <= bestScore + 12);\n\n        if (keepLast) active[n++] = lastPattern;\n        active[n++] = bestPat;\n        if (secondPat != -1 && secondPat != bestPat && secondPat != lastPattern) active[n++] = secondPat;\n        else if (thirdPat != -1 && thirdPat != bestPat && thirdPat != lastPattern) active[n++] = thirdPat;\n\n        return n;\n    }\n\n    static inline int softmin2(int a, int b) {\n        if (a > b) swap(a, b);\n        return (3 * a + b) / 4;\n    }\n\n    static inline int softmin3(int a, int b, int c) {\n        if (a > b) swap(a, b);\n        if (b > c) swap(b, c);\n        if (a > b) swap(a, b);\n        return (3 * a + b) / 4;\n    }\n\n    inline void scan_local(const Board &b, const int *active, int nActive,\n                           int &sameAdj, int &diffAdj, int &penalty) const {\n        sameAdj = diffAdj = 0;\n\n        int s0 = 0, s1 = 0, s2 = 0;\n        int pat0 = active[0];\n        int pat1 = (nActive >= 2 ? active[1] : active[0]);\n        int pat2 = (nActive >= 3 ? active[2] : active[0]);\n\n        for (int r = 0; r < 10; ++r) {\n            int base = r * 10;\n            for (int c = 0; c < 10; ++c) {\n                int id = base + c;\n                uint8_t col = b.a[id];\n                if (!col) continue;\n\n                s0 += distCost[pat0][id][col];\n                if (nActive >= 2) s1 += distCost[pat1][id][col];\n                if (nActive >= 3) s2 += distCost[pat2][id][col];\n\n                if (c + 1 < 10 && b.a[id + 1]) {\n                    if (b.a[id + 1] == col) ++sameAdj;\n                    else ++diffAdj;\n                }\n                if (r + 1 < 10 && b.a[id + 10]) {\n                    if (b.a[id + 10] == col) ++sameAdj;\n                    else ++diffAdj;\n                }\n            }\n        }\n\n        if (nActive == 1) penalty = s0;\n        else if (nActive == 2) penalty = softmin2(s0, s1);\n        else penalty = softmin3(s0, s1, s2);\n    }\n\n    long long heuristic_fast(const Board &b, int step, const int *active, int nActive) const {\n        int sameAdj, diffAdj, pen;\n        scan_local(b, active, nActive, sameAdj, diffAdj, pen);\n\n        int rem = 100 - step;\n        long long wPat = 10 + rem / 5;\n\n        return 72LL * sameAdj\n             - 48LL * diffAdj\n             - wPat * pen;\n    }\n\n    long long heuristic_full(const Board &b, int step, const int *active, int nActive) const {\n        int sameAdj, diffAdj, pen;\n        scan_local(b, active, nActive, sameAdj, diffAdj, pen);\n\n        int largest[4] = {};\n        int compCnt[4] = {};\n        int compSq = 0;\n\n        uint8_t vis[100] = {};\n        int q[100];\n\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n\n            compSq += sz * sz;\n            largest[col] = max(largest[col], sz);\n            compCnt[col]++;\n        }\n\n        long long optimistic = compSq;\n        long long futureFragPenalty = 0;\n        int curFragments = 0;\n\n        for (int c = 1; c <= 3; ++c) {\n            int remc = suffixCnt[step + 1][c];\n            optimistic += 2LL * largest[c] * remc;\n            futureFragPenalty += 1LL * max(0, compCnt[c] - 1) * remc;\n            curFragments += max(0, compCnt[c] - 1);\n        }\n\n        int rem = 100 - step;\n        long long wPat = 14 + rem / 4;\n\n        return optimistic * 1000LL\n             - futureFragPenalty * 220LL\n             - 95LL * curFragments * curFragments\n             + 50LL * sameAdj\n             - 34LL * diffAdj\n             - wPat * pen;\n    }\n\n    double exact_expect(const Board &state_after_tilt, int step) {\n        int next = step + 1;\n        int empties[100];\n        int m = collect_empties(state_after_tilt, empties);\n\n        if (m == 0) return comp_sq_only(state_after_tilt);\n\n        double sum = 0.0;\n        Board b, tmp;\n\n        for (int i = 0; i < m; ++i) {\n            b = state_after_tilt;\n            b.a[empties[i]] = (uint8_t)flavor[next];\n\n            if (next == 100) {\n                sum += comp_sq_only(b);\n            } else {\n                double best = -1e100;\n                for (int d = 0; d < 4; ++d) {\n                    apply_tilt(b, d, tmp);\n                    best = max(best, exact_expect(tmp, next));\n                }\n                sum += best;\n            }\n        }\n        return sum / m;\n    }\n\n    double one_step_expect(const Board &state_after_tilt, int step, const int *active, int nActive) {\n        int next = step + 1;\n        int empties[100];\n        int m = collect_empties(state_after_tilt, empties);\n\n        if (m == 0) return 0.0;\n\n        double sum = 0.0;\n        Board b, tmp;\n\n        for (int i = 0; i < m; ++i) {\n            b = state_after_tilt;\n            b.a[empties[i]] = (uint8_t)flavor[next];\n\n            if (next == 100) {\n                sum += 3000.0 * comp_sq_only(b);\n            } else {\n                long long best = LLONG_MIN;\n                for (int d = 0; d < 4; ++d) {\n                    apply_tilt(b, d, tmp);\n                    long long v = heuristic_full(tmp, next, active, nActive);\n                    if (v > best) best = v;\n                }\n                sum += (double)best;\n            }\n        }\n\n        return sum / m;\n    }\n\n    int choose_dir(const Board &after_insert, int step) {\n        if (step == 100) return 0;\n\n        Board first[4];\n        for (int d = 0; d < 4; ++d) apply_tilt(after_insert, d, first[d]);\n\n        int active[3];\n        int nActive = select_active_patterns(first, active);\n\n        long long baseH[4];\n        for (int d = 0; d < 4; ++d) baseH[d] = heuristic_full(first[d], step, active, nActive);\n\n        int greedyBest = 0;\n        for (int d = 1; d < 4; ++d) {\n            if (baseH[d] > baseH[greedyBest]) greedyBest = d;\n        }\n\n        auto finalize_pattern = [&](int bestD) {\n            lastPattern = best_pattern_for_board(first[bestD]);\n        };\n\n        if (elapsed() > TIME_LIMIT - 0.03) {\n            finalize_pattern(greedyBest);\n            return greedyBest;\n        }\n\n        int rem = 100 - step;\n\n        // Exact endgame\n        if (rem <= 5 && elapsed() < TIME_LIMIT - 0.03) {\n            double bestVal = -1e100;\n            int bestD = greedyBest;\n            for (int d = 0; d < 4; ++d) {\n                if (elapsed() > TIME_LIMIT - 0.02) break;\n                double v = exact_expect(first[d], step);\n                if (v > bestVal + 1e-12 || (fabs(v - bestVal) <= 1e-12 && baseH[d] > baseH[bestD])) {\n                    bestVal = v;\n                    bestD = d;\n                }\n            }\n            finalize_pattern(bestD);\n            return bestD;\n        }\n\n        // Exact one-step expectation\n        double nextH[4];\n        for (int d = 0; d < 4; ++d) nextH[d] = (double)baseH[d];\n\n        if (elapsed() < TIME_LIMIT - 0.08) {\n            for (int d = 0; d < 4; ++d) {\n                if (elapsed() > TIME_LIMIT - 0.05) break;\n                nextH[d] = one_step_expect(first[d], step, active, nActive);\n            }\n        }\n\n        // Truncated common-random-number rollouts with fast greedy policy\n        long double rollVal[4];\n        for (int d = 0; d < 4; ++d) rollVal[d] = nextH[d];\n\n        int H = 0, K = 0;\n        if (rem > 60) { H = 8; K = 4; }\n        else if (rem > 35) { H = 10; K = 5; }\n        else if (rem > 20) { H = 12; K = 6; }\n        else if (rem > 10) { H = rem; K = 7; }\n        else if (rem > 5) { H = rem; K = 9; }\n\n        double left = TIME_LIMIT - elapsed();\n        if (left < 0.30) K = max(0, K - 2);\n        if (left < 0.18) K = max(0, K - 2);\n        if (left < 0.10) K = 0;\n\n        if (K > 0) {\n            long long sumLeaf[4] = {};\n            int done = 0;\n            int ranks[101];\n            Board sim, tmp, bestBoard;\n\n            int endStep = min(100, step + H);\n\n            for (int it = 0; it < K; ++it) {\n                if (elapsed() > TIME_LIMIT - 0.02) break;\n\n                for (int u = step + 1; u <= endStep; ++u) {\n                    ranks[u] = 1 + rng.next_int(101 - u);\n                }\n\n                for (int d = 0; d < 4; ++d) {\n                    sim = first[d];\n\n                    for (int u = step + 1; u <= endStep; ++u) {\n                        place_by_rank(sim, ranks[u], flavor[u]);\n                        if (u == 100) break;\n\n                        long long bestF = LLONG_MIN;\n                        for (int nd = 0; nd < 4; ++nd) {\n                            apply_tilt(sim, nd, tmp);\n                            long long fv = heuristic_fast(tmp, u, active, nActive);\n                            if (fv > bestF) {\n                                bestF = fv;\n                                bestBoard = tmp;\n                            }\n                        }\n                        sim = bestBoard;\n                    }\n\n                    if (endStep == 100) sumLeaf[d] += 3000LL * comp_sq_only(sim);\n                    else sumLeaf[d] += heuristic_full(sim, endStep, active, nActive);\n                }\n                ++done;\n            }\n\n            if (done > 0) {\n                for (int d = 0; d < 4; ++d) {\n                    rollVal[d] = (long double)sumLeaf[d] / done;\n                }\n            }\n        }\n\n        long double bestScore = -1e300L;\n        int bestD = greedyBest;\n\n        long double wb, wn, wr;\n        if (rem > 40) {\n            wb = 0.15L; wn = 0.60L; wr = 0.25L;\n        } else if (rem > 15) {\n            wb = 0.20L; wn = 0.50L; wr = 0.30L;\n        } else {\n            wb = 0.20L; wn = 0.35L; wr = 0.45L;\n        }\n        if (K == 0) { wb = 0.30L; wn = 0.70L; wr = 0.0L; }\n\n        for (int d = 0; d < 4; ++d) {\n            long double score = wb * (long double)baseH[d]\n                              + wn * (long double)nextH[d]\n                              + wr * rollVal[d];\n            if (score > bestScore + 1e-12L ||\n                (fabsl(score - bestScore) <= 1e-12L && baseH[d] > baseH[bestD])) {\n                bestScore = score;\n                bestD = d;\n            }\n        }\n\n        finalize_pattern(bestD);\n        return bestD;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 1; i <= 100; ++i) {\n            cin >> flavor[i];\n            totalCnt[flavor[i]]++;\n        }\n\n        for (int c = 1; c <= 3; ++c) suffixCnt[101][c] = 0;\n        for (int t = 100; t >= 1; --t) {\n            for (int c = 1; c <= 3; ++c) suffixCnt[t][c] = suffixCnt[t + 1][c];\n            suffixCnt[t][flavor[t]]++;\n        }\n\n        init_patterns();\n\n        uint64_t seed = 0x123456789abcdefULL;\n        for (int i = 1; i <= 100; ++i) {\n            seed = seed * 6364136223846793005ULL + (uint64_t)(flavor[i] + 17);\n        }\n        rng = SplitMix64(seed);\n\n        cur.a.fill(0);\n        st = chrono::steady_clock::now();\n\n        for (int t = 1; t <= 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place_by_rank(cur, p, flavor[t]);\n\n            int d = choose_dir(cur, t);\n\n            Board nxt;\n            apply_tilt(cur, d, nxt);\n            cur = nxt;\n\n            cout << DIR_CH[d] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\n\n// ============================================================\n// Utility\n// ============================================================\n\nstatic double expected_score_from_err_rate(double p_err, int N) {\n    p_err = max(0.0, min(1.0, p_err));\n    return pow(0.9, 100.0 * p_err) / N;\n}\nstatic double score_from_counts(int err, int tot, int N) {\n    double p = (err + 0.5) / (tot + 1.0);\n    return expected_score_from_err_rate(p, N);\n}\n\nstatic vector<int> sample_ids_evenly(int M, int S) {\n    S = min(S, M);\n    vector<int> ids;\n    ids.reserve(S);\n    for (int t = 0; t < S; t++) {\n        int id = (long long)t * M / S;\n        if (ids.empty() || ids.back() != id) ids.push_back(id);\n    }\n    if ((int)ids.size() < S) {\n        vector<char> used(M, 0);\n        for (int x : ids) used[x] = 1;\n        for (int i = 0; i < M && (int)ids.size() < S; i++) {\n            if (!used[i]) ids.push_back(i);\n        }\n        sort(ids.begin(), ids.end());\n    }\n    return ids;\n}\n\n// ============================================================\n// Small exact / low-noise family (N <= 6)\n// ============================================================\n\nstruct SmallDB {\n    int N = 0, E = 0, maskCnt = 0, P = 0;\n    vector<pair<int,int>> edges;\n    vector<uint16_t> reps;\n    vector<vector<uint16_t>> repPermMasks;\n    vector<vector<uint8_t>> dist;\n    vector<vector<int>> permMaps;\n};\n\nstatic SmallDB init_small_db(int N) {\n    SmallDB db;\n    db.N = N;\n\n    int edgeIndex[8][8];\n    memset(edgeIndex, -1, sizeof(edgeIndex));\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            edgeIndex[i][j] = edgeIndex[j][i] = (int)db.edges.size();\n            db.edges.push_back({i, j});\n        }\n    }\n    db.E = (int)db.edges.size();\n    db.maskCnt = 1 << db.E;\n\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n    do {\n        vector<int> mp(db.E);\n        for (int e = 0; e < db.E; e++) {\n            auto [u, v] = db.edges[e];\n            int a = perm[u], b = perm[v];\n            if (a > b) swap(a, b);\n            mp[e] = edgeIndex[a][b];\n        }\n        db.permMaps.push_back(std::move(mp));\n    } while (next_permutation(perm.begin(), perm.end()));\n    db.P = (int)db.permMaps.size();\n\n    vector<uint16_t> permTable((size_t)db.P * db.maskCnt);\n    for (int p = 0; p < db.P; p++) {\n        size_t base = (size_t)p * db.maskCnt;\n        permTable[base] = 0;\n        for (int mask = 1; mask < db.maskCnt; mask++) {\n            int lb = mask & -mask;\n            int bit = __builtin_ctz(lb);\n            int prev = mask ^ lb;\n            permTable[base + mask] = permTable[base + prev] | (uint16_t(1) << db.permMaps[p][bit]);\n        }\n    }\n\n    vector<char> seen(db.maskCnt, 0);\n    for (int mask = 0; mask < db.maskCnt; mask++) {\n        uint16_t best = numeric_limits<uint16_t>::max();\n        for (int p = 0; p < db.P; p++) {\n            uint16_t x = permTable[(size_t)p * db.maskCnt + mask];\n            if (x < best) best = x;\n        }\n        if (!seen[best]) {\n            seen[best] = 1;\n            db.reps.push_back(best);\n        }\n    }\n    sort(db.reps.begin(), db.reps.end());\n\n    int C = (int)db.reps.size();\n    db.repPermMasks.resize(C);\n    for (int i = 0; i < C; i++) {\n        uint16_t rep = db.reps[i];\n        auto& vv = db.repPermMasks[i];\n        vv.reserve(db.P);\n        for (int p = 0; p < db.P; p++) {\n            vv.push_back(permTable[(size_t)p * db.maskCnt + rep]);\n        }\n        sort(vv.begin(), vv.end());\n        vv.erase(unique(vv.begin(), vv.end()), vv.end());\n    }\n\n    db.dist.assign(C, vector<uint8_t>(C, 0));\n    for (int i = 0; i < C; i++) {\n        for (int j = i + 1; j < C; j++) {\n            int best = db.E + 1;\n            for (uint16_t pm : db.repPermMasks[j]) {\n                int d = __builtin_popcount((unsigned)(db.reps[i] ^ pm));\n                if (d < best) best = d;\n                if (best == 0) break;\n            }\n            db.dist[i][j] = db.dist[j][i] = (uint8_t)best;\n        }\n    }\n\n    return db;\n}\n\nstatic uint16_t canonicalize_small(const SmallDB& db, uint16_t mask) {\n    uint16_t best = numeric_limits<uint16_t>::max();\n    for (int p = 0; p < db.P; p++) {\n        uint16_t y = 0;\n        for (int b = 0; b < db.E; b++) {\n            if ((mask >> b) & 1) y |= (uint16_t(1) << db.permMaps[p][b]);\n        }\n        if (y < best) best = y;\n    }\n    return best;\n}\n\nstatic string small_mask_to_string(uint16_t mask, int E) {\n    string s(E, '0');\n    for (int i = 0; i < E; i++) if ((mask >> i) & 1) s[i] = '1';\n    return s;\n}\n\nstatic double small_selection_quality(const SmallDB& db, const vector<int>& sel) {\n    if (sel.size() <= 1) return 0.0;\n    double sum = 0.0;\n    for (int i = 0; i < (int)sel.size(); i++) {\n        int best = 1e9;\n        for (int j = 0; j < (int)sel.size(); j++) if (i != j) {\n            best = min(best, (int)db.dist[sel[i]][sel[j]]);\n        }\n        sum += best;\n    }\n    return sum / sel.size();\n}\n\nstatic vector<int> select_small_code_indices(const SmallDB& db, int M) {\n    int C = (int)db.reps.size();\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        int ea = __builtin_popcount((unsigned)db.reps[a]);\n        int eb = __builtin_popcount((unsigned)db.reps[b]);\n        if (ea != eb) return ea < eb;\n        return db.reps[a] < db.reps[b];\n    });\n\n    if (C <= M) return idx;\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2], idx[C / 3], idx[(2 * C) / 3]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQ = -1.0;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<int> minDist(C, 1e9);\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                minDist[i] = min(minDist[i], (int)db.dist[x][i]);\n            }\n        };\n\n        add_one(seed);\n        while ((int)sel.size() < M) {\n            int nxt = -1, best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double q = small_selection_quality(db, sel);\n        if (q > bestQ) {\n            bestQ = q;\n            bestSel = sel;\n        }\n    }\n\n    sort(bestSel.begin(), bestSel.end(), [&](int a, int b) {\n        int ea = __builtin_popcount((unsigned)db.reps[a]);\n        int eb = __builtin_popcount((unsigned)db.reps[b]);\n        if (ea != eb) return ea < eb;\n        return db.reps[a] < db.reps[b];\n    });\n    return bestSel;\n}\n\nstruct SmallStrategy {\n    int N = 0, E = 0, M = 0;\n    vector<uint16_t> codeMasks;\n    vector<vector<uint16_t>> codePermMasks;\n    vector<string> graphStrs;\n    double estScore = -1.0;\n};\n\nstatic int decode_small(const SmallStrategy& st, uint16_t mask) {\n    int bestId = 0;\n    int bestDist = st.E + 1;\n    for (int i = 0; i < st.M; i++) {\n        int curBest = st.E + 1;\n        for (uint16_t pm : st.codePermMasks[i]) {\n            int d = __builtin_popcount((unsigned)(mask ^ pm));\n            if (d < curBest) curBest = d;\n            if (curBest == 0) break;\n        }\n        if (curBest < bestDist) {\n            bestDist = curBest;\n            bestId = i;\n        }\n    }\n    return bestId;\n}\n\nstatic double estimate_small_strategy(SmallStrategy& st, double eps, int reps, uint64_t seed) {\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    int err = 0, tot = 0;\n    for (int i = 0; i < st.M; i++) {\n        uint16_t base = st.codeMasks[i];\n        for (int r = 0; r < reps; r++) {\n            uint16_t noisy = base;\n            for (int b = 0; b < st.E; b++) {\n                if (ur(rng) < eps) noisy ^= (uint16_t(1) << b);\n            }\n            int ans = decode_small(st, noisy);\n            if (ans != i) err++;\n            tot++;\n        }\n    }\n    return score_from_counts(err, tot, st.N);\n}\n\n// ============================================================\n// Generic base-candidate representation\n// ============================================================\n\nstruct BaseCand {\n    int B = 0;\n    string baseStr;            // base graph on B vertices\n    bool insideClique = false; // each blown-up base vertex becomes a clique or an independent set\n    int edgeBase = 0;\n    int triBase = 0;\n    vector<int> degBaseSorted;\n    vector<int> ndBaseSorted;\n    int familyTag = 0;\n\n    vector<int> degBase;       // unsorted, indexed by base vertex\n    vector<uint32_t> adjMask;  // unsorted, bitset by base vertex\n};\n\nstatic bool cand_less(const BaseCand& a, const BaseCand& b) {\n    if (a.edgeBase != b.edgeBase) return a.edgeBase < b.edgeBase;\n    if (a.insideClique != b.insideClique) return a.insideClique < b.insideClique;\n    if (a.familyTag != b.familyTag) return a.familyTag < b.familyTag;\n    return a.baseStr < b.baseStr;\n}\n\nstatic string build_partition_base_string(const vector<int>& parts, int type) {\n    int B = 0;\n    for (int x : parts) B += x;\n\n    vector<int> block(B);\n    int ptr = 0, bid = 0;\n    for (int x : parts) {\n        for (int i = 0; i < x; i++) block[ptr++] = bid;\n        bid++;\n    }\n\n    string g;\n    g.reserve(B * (B - 1) / 2);\n    for (int i = 0; i < B; i++) {\n        for (int j = i + 1; j < B; j++) {\n            bool same = (block[i] == block[j]);\n            bool e = (type == 0 ? same : !same);\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic string build_threshold_base_string(int B, uint32_t mask) {\n    string g;\n    g.reserve(B * (B - 1) / 2);\n    for (int i = 0; i < B; i++) {\n        for (int j = i + 1; j < B; j++) {\n            bool e = ((mask >> (j - 1)) & 1u) != 0;\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic void analyze_base_candidate(BaseCand& c) {\n    int B = c.B;\n    int deg[MAXN] = {};\n    int nd[MAXN] = {};\n    vector<uint32_t> adjMask(B, 0);\n\n    int pos = 0;\n    for (int i = 0; i < B; i++) {\n        for (int j = i + 1; j < B; j++) {\n            unsigned char bit = (unsigned char)(c.baseStr[pos++] - '0');\n            if (bit) {\n                adjMask[i] |= (1u << j);\n                adjMask[j] |= (1u << i);\n                deg[i]++;\n                deg[j]++;\n                c.edgeBase++;\n            }\n        }\n    }\n\n    for (int i = 0; i < B; i++) {\n        int s = 0;\n        uint32_t m = adjMask[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= (m - 1);\n            s += deg[j];\n        }\n        nd[i] = s;\n    }\n\n    vector<pair<int,int>> feat(B);\n    for (int i = 0; i < B; i++) feat[i] = {deg[i], nd[i]};\n    sort(feat.begin(), feat.end());\n    c.degBaseSorted.resize(B);\n    c.ndBaseSorted.resize(B);\n    for (int i = 0; i < B; i++) {\n        c.degBaseSorted[i] = feat[i].first;\n        c.ndBaseSorted[i] = feat[i].second;\n    }\n\n    c.degBase.assign(deg, deg + B);\n    c.adjMask = std::move(adjMask);\n\n    int tri = 0;\n    for (int i = 0; i < B; i++) {\n        uint32_t mi = c.adjMask[i];\n        while (mi) {\n            int j = __builtin_ctz(mi);\n            mi &= (mi - 1);\n            if (j <= i) continue;\n            uint32_t common = c.adjMask[i] & c.adjMask[j];\n            while (common) {\n                int k = __builtin_ctz(common);\n                common &= (common - 1);\n                if (k > j) tri++;\n            }\n        }\n    }\n    c.triBase = tri;\n}\n\nstatic void gen_partitions_rec(int rem, int last, bool distinctOnly, vector<int>& cur, vector<vector<int>>& out) {\n    if (rem == 0) {\n        out.push_back(cur);\n        return;\n    }\n    for (int x = last; x <= rem; x++) {\n        cur.push_back(x);\n        gen_partitions_rec(rem - x, distinctOnly ? x + 1 : x, distinctOnly, cur, out);\n        cur.pop_back();\n    }\n}\n\nstatic vector<vector<int>> generate_partitions(int B, bool distinctOnly) {\n    vector<vector<int>> out;\n    vector<int> cur;\n    gen_partitions_rec(B, 1, distinctOnly, cur, out);\n    return out;\n}\n\nstatic vector<BaseCand> generate_partition_candidates(int B, bool distinctOnly, int familyTag) {\n    auto plist = generate_partitions(B, distinctOnly);\n    vector<BaseCand> res;\n    unordered_set<string> seen;\n\n    for (const auto& parts : plist) {\n        for (int type = 0; type <= 1; type++) {\n            BaseCand c;\n            c.B = B;\n            c.baseStr = build_partition_base_string(parts, type);\n            c.insideClique = (type == 0);\n            c.familyTag = familyTag;\n            string key;\n            key.reserve(1 + c.baseStr.size());\n            key.push_back(c.insideClique ? '1' : '0');\n            key += c.baseStr;\n            if (!seen.insert(key).second) continue;\n            analyze_base_candidate(c);\n            res.push_back(std::move(c));\n        }\n    }\n\n    sort(res.begin(), res.end(), cand_less);\n    return res;\n}\n\nstatic vector<BaseCand> generate_threshold_candidates(int B, bool insideClique, int familyTag) {\n    vector<BaseCand> res;\n    uint32_t lim = 1u << (B - 1);\n    res.reserve(lim);\n\n    for (uint32_t mask = 0; mask < lim; mask++) {\n        BaseCand c;\n        c.B = B;\n        c.baseStr = build_threshold_base_string(B, mask);\n        c.insideClique = insideClique;\n        c.familyTag = familyTag;\n        analyze_base_candidate(c);\n        res.push_back(std::move(c));\n    }\n\n    sort(res.begin(), res.end(), cand_less);\n    return res;\n}\n\nstatic vector<BaseCand> merge_unique_pools(const vector<vector<BaseCand>>& pools) {\n    vector<BaseCand> res;\n    unordered_set<string> seen;\n    for (const auto& pool : pools) {\n        for (const auto& c : pool) {\n            string key;\n            key.reserve(1 + c.baseStr.size());\n            key.push_back(c.insideClique ? '1' : '0');\n            key += c.baseStr;\n            if (seen.insert(key).second) res.push_back(c);\n        }\n    }\n    sort(res.begin(), res.end(), cand_less);\n    return res;\n}\n\n// ============================================================\n// q+eps-aware block-level selection features\n// ============================================================\n\nstruct SelFeat {\n    vector<float> muDegB; // length B, sorted by (muDeg, muNd)\n    vector<float> muNdB;  // length B, same order\n};\n\nstatic SelFeat build_selection_feature(const BaseCand& c, int q, double eps) {\n    int B = c.B;\n    int N = B * q;\n\n    vector<double> muDeg(B), muNd(B);\n    double addInside = c.insideClique ? (q - 1) : 0.0;\n    double shift = eps * (N - 1);\n    double scale = 1.0 - 2.0 * eps;\n\n    for (int i = 0; i < B; i++) {\n        double dclean = 1.0 * q * c.degBase[i] + addInside;\n        muDeg[i] = shift + scale * dclean;\n    }\n\n    double pSame = c.insideClique ? (1.0 - eps) : eps;\n    for (int i = 0; i < B; i++) {\n        double s = (q - 1) * pSame * (1.0 + muDeg[i] - pSame);\n        uint32_t mask = c.adjMask[i];\n        for (int j = 0; j < B; j++) if (j != i) {\n            bool e = ((mask >> j) & 1u) != 0;\n            double p = e ? (1.0 - eps) : eps;\n            s += q * p * (1.0 + muDeg[j] - p);\n        }\n        muNd[i] = s;\n    }\n\n    vector<int> ord(B);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (muDeg[a] != muDeg[b]) return muDeg[a] < muDeg[b];\n        if (muNd[a] != muNd[b]) return muNd[a] < muNd[b];\n        return a < b;\n    });\n\n    SelFeat sf;\n    sf.muDegB.resize(B);\n    sf.muNdB.resize(B);\n    for (int i = 0; i < B; i++) {\n        sf.muDegB[i] = (float)muDeg[ord[i]];\n        sf.muNdB[i] = (float)muNd[ord[i]];\n    }\n    return sf;\n}\n\nstatic double selection_distance(const SelFeat& a, const SelFeat& b, int q, int N, double eps) {\n    int B = (int)a.muDegB.size();\n    double dDeg = 0.0, dNd = 0.0;\n    for (int i = 0; i < B; i++) {\n        double x = (double)a.muDegB[i] - b.muDegB[i];\n        double y = (double)a.muNdB[i] - b.muNdB[i];\n        dDeg += x * x;\n        dNd += y * y;\n    }\n    dDeg *= q;\n    dNd *= q;\n\n    double alphaNd;\n    if (eps <= 0.10) alphaNd = 0.18;\n    else if (eps <= 0.20) alphaNd = 0.12;\n    else if (eps <= 0.30) alphaNd = 0.08;\n    else alphaNd = 0.05;\n\n    return dDeg + alphaNd * dNd / max(1.0, 1.0 * N * N);\n}\n\nstatic double selection_quality(const vector<SelFeat>& feats, const vector<int>& sel, int q, int N, double eps) {\n    if (sel.size() <= 1) return 0.0;\n    double sum = 0.0;\n    for (int i = 0; i < (int)sel.size(); i++) {\n        double best = 1e100;\n        for (int j = 0; j < (int)sel.size(); j++) if (i != j) {\n            best = min(best, selection_distance(feats[sel[i]], feats[sel[j]], q, N, eps));\n        }\n        sum += best;\n    }\n    return sum / sel.size();\n}\n\nstatic vector<int> select_code_indices_qaware(const vector<BaseCand>& pool, int M, int q, double eps) {\n    int C = (int)pool.size();\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n\n    if (C <= M) {\n        sort(idx.begin(), idx.end(), [&](int a, int b) { return cand_less(pool[a], pool[b]); });\n        return idx;\n    }\n\n    int B = pool[0].B;\n    int N = B * q;\n    vector<SelFeat> feats(C);\n    for (int i = 0; i < C; i++) feats[i] = build_selection_feature(pool[i], q, eps);\n\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        return cand_less(pool[a], pool[b]);\n    });\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2], idx[C / 3], idx[(2 * C) / 3]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQual = -1.0;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<double> minDist(C, 1e100);\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                double d = selection_distance(feats[x], feats[i], q, N, eps);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        };\n\n        add_one(seed);\n        if (M >= 2) {\n            int far = -1;\n            double best = -1.0;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                double d = selection_distance(feats[seed], feats[i], q, N, eps);\n                if (d > best) {\n                    best = d;\n                    far = i;\n                }\n            }\n            add_one(far);\n        }\n\n        while ((int)sel.size() < M) {\n            int nxt = -1;\n            double best = -1.0;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double qual = selection_quality(feats, sel, q, N, eps);\n        if (qual > bestQual) {\n            bestQual = qual;\n            bestSel = sel;\n        }\n    }\n\n    sort(bestSel.begin(), bestSel.end(), [&](int a, int b) {\n        return cand_less(pool[a], pool[b]);\n    });\n    return bestSel;\n}\n\nstatic vector<BaseCand> materialize_selected(const vector<BaseCand>& pool, const vector<int>& sel) {\n    vector<BaseCand> ret;\n    ret.reserve(sel.size());\n    for (int id : sel) ret.push_back(pool[id]);\n    sort(ret.begin(), ret.end(), cand_less);\n    return ret;\n}\n\n// ============================================================\n// Generic graph construction from base graph + inside policy\n// ============================================================\n\nstatic string build_full_graph_string(const BaseCand& c, int q) {\n    int B = c.B;\n    int N = B * q;\n\n    string g;\n    g.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        int bi = i / q;\n        for (int j = i + 1; j < N; j++) {\n            int bj = j / q;\n            bool e = (bi == bj ? c.insideClique : ((c.adjMask[bi] >> bj) & 1u));\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic vector<double> build_proxy_expected_mu(const BaseCand& c, int q, double eps) {\n    int N = c.B * q;\n    double shift = eps * (N - 1);\n    double scale = 1.0 - 2.0 * eps;\n    double add = c.insideClique ? (q - 1) : 0.0;\n\n    vector<double> mu;\n    mu.reserve(N);\n    for (int d0 : c.degBaseSorted) {\n        double d = q * d0 + add;\n        double m = shift + scale * d;\n        for (int t = 0; t < q; t++) mu.push_back(m);\n    }\n    return mu;\n}\n\n// ============================================================\n// Codebook and decoder\n// ============================================================\n\nstruct Codebook {\n    int N = 0, M = 0;\n    double eps = 0.0;\n    double sigma2 = 0.0;\n    vector<string> graphStrs;\n    vector<vector<double>> muDeg;\n    vector<vector<double>> muNd;\n    vector<double> triMu, triVar;\n    double estScore = -1.0;\n};\n\nstatic Codebook build_codebook(const vector<BaseCand>& codes, int q, double eps) {\n    Codebook cb;\n    cb.M = (int)codes.size();\n    cb.N = codes[0].B * q;\n    cb.eps = eps;\n    cb.sigma2 = (cb.N - 1) * eps * (1.0 - eps);\n\n    cb.graphStrs.reserve(cb.M);\n    cb.muDeg.reserve(cb.M);\n    cb.muNd.reserve(cb.M);\n    cb.triMu.reserve(cb.M);\n    cb.triVar.reserve(cb.M);\n\n    static unsigned char adj[MAXN][MAXN];\n    static double p[MAXN][MAXN];\n    int N = cb.N;\n\n    for (const auto& c : codes) {\n        string g = build_full_graph_string(c, q);\n        cb.graphStrs.push_back(g);\n\n        int deg[MAXN] = {};\n        int pos = 0;\n        for (int i = 0; i < N; i++) adj[i][i] = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                unsigned char bit = (unsigned char)(g[pos++] - '0');\n                adj[i][j] = adj[j][i] = bit;\n                if (bit) {\n                    deg[i]++;\n                    deg[j]++;\n                }\n            }\n        }\n\n        double muDegRaw[MAXN];\n        for (int i = 0; i < N; i++) {\n            muDegRaw[i] = eps * (N - 1) + (1.0 - 2.0 * eps) * deg[i];\n        }\n\n        for (int i = 0; i < N; i++) {\n            p[i][i] = 0.0;\n            for (int j = i + 1; j < N; j++) {\n                double pij = adj[i][j] ? (1.0 - eps) : eps;\n                p[i][j] = p[j][i] = pij;\n            }\n        }\n\n        double muNdRaw[MAXN];\n        for (int i = 0; i < N; i++) {\n            double s = 0.0;\n            for (int j = 0; j < N; j++) if (i != j) {\n                s += p[i][j] * (1.0 + muDegRaw[j] - p[i][j]);\n            }\n            muNdRaw[i] = s;\n        }\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (muDegRaw[a] != muDegRaw[b]) return muDegRaw[a] < muDegRaw[b];\n            if (muNdRaw[a] != muNdRaw[b]) return muNdRaw[a] < muNdRaw[b];\n            return a < b;\n        });\n\n        vector<double> md(N), mn(N);\n        for (int i = 0; i < N; i++) {\n            md[i] = muDegRaw[ord[i]];\n            mn[i] = muNdRaw[ord[i]];\n        }\n        cb.muDeg.push_back(std::move(md));\n        cb.muNd.push_back(std::move(mn));\n\n        long long cnt[4] = {};\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                for (int k = j + 1; k < N; k++) {\n                    int e = adj[i][j] + adj[i][k] + adj[j][k];\n                    cnt[e]++;\n                }\n            }\n        }\n\n        double a = 1.0 - eps, b = eps;\n        double triMean = 0.0;\n        triMean += cnt[3] * (a * a * a);\n        triMean += cnt[2] * (a * a * b);\n        triMean += cnt[1] * (a * b * b);\n        triMean += cnt[0] * (b * b * b);\n\n        double total = cnt[0] + cnt[1] + cnt[2] + cnt[3];\n        double pTri = (total > 0 ? triMean / total : 0.0);\n        double triVar = max(1.0, 4.0 * total * pTri * (1.0 - pTri));\n\n        cb.triMu.push_back(triMean);\n        cb.triVar.push_back(triVar);\n    }\n\n    return cb;\n}\n\nstatic int count_triangles(const unsigned char adj[MAXN][MAXN], int N) {\n    int tri = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) if (adj[i][j]) {\n            for (int k = j + 1; k < N; k++) {\n                if (adj[i][k] && adj[j][k]) tri++;\n            }\n        }\n    }\n    return tri;\n}\n\nstatic int decode_codebook(const Codebook& cb, const unsigned char adj[MAXN][MAXN]) {\n    int N = cb.N, M = cb.M;\n\n    int deg[MAXN] = {};\n    int nd[MAXN] = {};\n\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) if (adj[i][j]) {\n            deg[i]++;\n            deg[j]++;\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        int s = 0;\n        for (int j = 0; j < N; j++) if (adj[i][j]) s += deg[j];\n        nd[i] = s;\n    }\n\n    vector<pair<int,int>> obs(N);\n    for (int i = 0; i < N; i++) obs[i] = {deg[i], nd[i]};\n    sort(obs.begin(), obs.end());\n\n    vector<int> obsDeg(N), obsNd(N);\n    for (int i = 0; i < N; i++) {\n        obsDeg[i] = obs[i].first;\n        obsNd[i] = obs[i].second;\n    }\n\n    if (cb.sigma2 < 1e-12) {\n        int bestId = 0;\n        double best = 1e100;\n        for (int k = 0; k < M; k++) {\n            double s = 0.0;\n            const auto& mu = cb.muDeg[k];\n            for (int i = 0; i < N; i++) {\n                double d = obsDeg[i] - mu[i];\n                s += d * d;\n            }\n            if (s < best) {\n                best = s;\n                bestId = k;\n            }\n        }\n        return bestId;\n    }\n\n    vector<double> degSse(M), ndSse(M), preScore(M);\n    double ndDen = max(1.0, cb.sigma2) * 1.0 * N * N * N;\n    double preBetaNd;\n    if (cb.eps <= 0.10) preBetaNd = 0.08;\n    else if (cb.eps <= 0.20) preBetaNd = 0.05;\n    else if (cb.eps <= 0.30) preBetaNd = 0.03;\n    else preBetaNd = 0.02;\n\n    vector<pair<double,int>> ord;\n    ord.reserve(M);\n    for (int k = 0; k < M; k++) {\n        double s1 = 0.0, s2 = 0.0;\n        const auto& md = cb.muDeg[k];\n        const auto& mn = cb.muNd[k];\n        for (int i = 0; i < N; i++) {\n            double a = obsDeg[i] - md[i];\n            double b = obsNd[i] - mn[i];\n            s1 += a * a;\n            s2 += b * b;\n        }\n        degSse[k] = s1;\n        ndSse[k] = s2;\n        double pre = s1 / (cb.sigma2 + 1e-9) + preBetaNd * s2 / ndDen;\n        preScore[k] = pre;\n        ord.push_back({pre, k});\n    }\n    sort(ord.begin(), ord.end());\n\n    int triObs = count_triangles(adj, N);\n\n    double betaNd;\n    if (cb.eps <= 0.10) betaNd = 0.32;\n    else if (cb.eps <= 0.20) betaNd = 0.23;\n    else if (cb.eps <= 0.30) betaNd = 0.14;\n    else betaNd = 0.10;\n    double betaTri = 0.16;\n\n    int K = min(M, 16);\n    int ans = ord[0].second;\n    double bestScore = 1e100;\n    for (int t = 0; t < K; t++) {\n        int id = ord[t].second;\n        double triZ = (triObs - cb.triMu[id]) * (triObs - cb.triMu[id]) / (cb.triVar[id] + 1.0);\n        double score = degSse[id] / (cb.sigma2 + 1e-9)\n                     + betaNd * ndSse[id] / ndDen\n                     + betaTri * triZ;\n        if (score < bestScore) {\n            bestScore = score;\n            ans = id;\n        }\n    }\n    return ans;\n}\n\nstatic double estimate_actual_score(const Codebook& cb, int sampleS, int reps, uint64_t seed) {\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur(0.0, 1.0);\n    auto ids = sample_ids_evenly(cb.M, sampleS);\n\n    static unsigned char adj[MAXN][MAXN];\n    int err = 0, tot = 0;\n\n    for (int id : ids) {\n        const string& g = cb.graphStrs[id];\n        for (int rep = 0; rep < reps; rep++) {\n            int pos = 0;\n            for (int i = 0; i < cb.N; i++) adj[i][i] = 0;\n            for (int i = 0; i < cb.N; i++) {\n                for (int j = i + 1; j < cb.N; j++) {\n                    unsigned char bit = (unsigned char)(g[pos++] - '0');\n                    if (ur(rng) < cb.eps) bit ^= 1;\n                    adj[i][j] = adj[j][i] = bit;\n                }\n            }\n            int ans = decode_codebook(cb, adj);\n            if (ans != id) err++;\n            tot++;\n        }\n    }\n\n    return score_from_counts(err, tot, cb.N);\n}\n\n// ============================================================\n// Proxy search\n// ============================================================\n\nstatic vector<int> q_candidates(int qmax) {\n    set<int> s;\n    for (int q = 1; q <= min(qmax, 8); q++) s.insert(q);\n    for (int q = 10; q <= qmax; q += 2) s.insert(q);\n    s.insert(qmax);\n    return vector<int>(s.begin(), s.end());\n}\n\nstatic double estimate_proxy_score(const vector<BaseCand>& codes, int q, double eps, int reps) {\n    int M = (int)codes.size();\n    int N = codes[0].B * q;\n    double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n\n    vector<vector<double>> exps(M);\n    for (int i = 0; i < M; i++) exps[i] = build_proxy_expected_mu(codes[i], q, eps);\n\n    mt19937_64 rng(0x123456789ULL + 10007ULL * codes[0].B + 1000003ULL * q);\n    normal_distribution<double> gauss(0.0, sigma);\n\n    vector<double> noisy(N);\n    int err = 0, tot = 0;\n\n    for (int rep = 0; rep < reps; rep++) {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < N; j++) {\n                double x = exps[i][j];\n                if (sigma > 0) x += gauss(rng);\n                x = max(0.0, min((double)(N - 1), x));\n                noisy[j] = x;\n            }\n            sort(noisy.begin(), noisy.end());\n\n            int bestId = 0;\n            double bestS = 1e100;\n            for (int t = 0; t < M; t++) {\n                double s = 0.0;\n                const auto& mu = exps[t];\n                for (int j = 0; j < N; j++) {\n                    double d = noisy[j] - mu[j];\n                    s += d * d;\n                    if (s >= bestS) break;\n                }\n                if (s < bestS) {\n                    bestS = s;\n                    bestId = t;\n                }\n            }\n            if (bestId != i) err++;\n            tot++;\n        }\n    }\n\n    return score_from_counts(err, tot, N);\n}\n\n// ============================================================\n// Main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    // --------------------------------------------------------\n    // Exact strategy for eps = 0\n    // --------------------------------------------------------\n    if (fabs(eps) < 1e-12) {\n        vector<int> Ns = {4, 5, 6};\n        SmallDB db;\n        int chosenN = -1;\n        for (int N : Ns) {\n            SmallDB cur = init_small_db(N);\n            if ((int)cur.reps.size() >= M) {\n                db = std::move(cur);\n                chosenN = N;\n                break;\n            }\n        }\n        if (chosenN == -1) {\n            db = init_small_db(6);\n            chosenN = 6;\n        }\n\n        vector<uint16_t> chosen(db.reps.begin(), db.reps.begin() + M);\n        unordered_map<int,int> repToIdx;\n        repToIdx.reserve(M * 2);\n        for (int i = 0; i < M; i++) repToIdx[(int)chosen[i]] = i;\n\n        cout << chosenN << '\\n';\n        for (int i = 0; i < M; i++) {\n            cout << small_mask_to_string(chosen[i], db.E) << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; q++) {\n            string H;\n            cin >> H;\n            uint16_t mask = 0;\n            for (int i = 0; i < db.E; i++) if (H[i] == '1') {\n                mask |= (uint16_t(1) << i);\n            }\n            uint16_t canon = canonicalize_small(db, mask);\n            int ans = repToIdx[(int)canon];\n            cout << ans << '\\n';\n            cout.flush();\n        }\n        return 0;\n    }\n\n    // --------------------------------------------------------\n    // Optional low-noise small strategy\n    // --------------------------------------------------------\n    SmallStrategy bestSmall;\n    bool hasSmall = false;\n    if (eps <= 0.03) {\n        vector<int> smallNs;\n        if (M <= 11) smallNs = {4, 5, 6};\n        else if (M <= 34) smallNs = {5, 6};\n        else smallNs = {6};\n\n        for (int N : smallNs) {\n            SmallDB db = init_small_db(N);\n            if ((int)db.reps.size() < M) continue;\n\n            auto sel = select_small_code_indices(db, M);\n\n            SmallStrategy st;\n            st.N = N;\n            st.E = N * (N - 1) / 2;\n            st.M = M;\n            st.codeMasks.reserve(M);\n            st.codePermMasks.reserve(M);\n            st.graphStrs.reserve(M);\n\n            for (int id : sel) {\n                st.codeMasks.push_back(db.reps[id]);\n                st.codePermMasks.push_back(db.repPermMasks[id]);\n                st.graphStrs.push_back(small_mask_to_string(db.reps[id], st.E));\n            }\n\n            st.estScore = estimate_small_strategy(st, eps, 8, 0xABCDEF123456789ULL + 10007ULL * N + M);\n            if (!hasSmall || st.estScore > bestSmall.estScore) {\n                hasSmall = true;\n                bestSmall = std::move(st);\n            }\n        }\n    }\n\n    // --------------------------------------------------------\n    // Build raw candidate pools\n    // --------------------------------------------------------\n    vector<vector<BaseCand>> rawPartAll(24), rawPartDistinct(24);\n    for (int B = 1; B <= 23; B++) {\n        rawPartAll[B] = generate_partition_candidates(B, false, 1);\n        rawPartDistinct[B] = generate_partition_candidates(B, true, 2);\n    }\n\n    vector<vector<BaseCand>> rawThInd(13), rawThCli(13), rawThMix(13), rawAllMix(13);\n    for (int B = 4; B <= 12; B++) {\n        rawThInd[B] = generate_threshold_candidates(B, false, 3);\n        rawThCli[B] = generate_threshold_candidates(B, true, 4);\n        rawThMix[B] = merge_unique_pools({rawThInd[B], rawThCli[B]});\n        rawAllMix[B] = merge_unique_pools({rawPartAll[B], rawThInd[B], rawThCli[B]});\n    }\n\n    struct Book {\n        int B;\n        string tag;\n        vector<BaseCand> pool;\n    };\n    vector<Book> books;\n\n    {\n        int Bmin = -1;\n        for (int B = 1; B <= 23; B++) {\n            if ((int)rawPartAll[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin == -1) Bmin = 23;\n        int Bhi = min(23, Bmin + 7);\n        for (int B = Bmin; B <= Bhi; B++) {\n            if ((int)rawPartAll[B].size() >= M) {\n                books.push_back({B, \"part_all\", rawPartAll[B]});\n            }\n        }\n    }\n\n    {\n        int Bmin = -1;\n        for (int B = 1; B <= 23; B++) {\n            if ((int)rawPartDistinct[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(23, Bmin + 5);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawPartDistinct[B].size() >= M) {\n                    books.push_back({B, \"part_distinct\", rawPartDistinct[B]});\n                }\n            }\n        }\n    }\n\n    {\n        int Bmin = -1;\n        for (int B = 4; B <= 12; B++) {\n            if ((int)rawThMix[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(12, Bmin + 4);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawThMix[B].size() >= M) {\n                    books.push_back({B, \"th_mix\", rawThMix[B]});\n                }\n            }\n        }\n    }\n\n    {\n        int Bmin = -1;\n        for (int B = 4; B <= 12; B++) {\n            if ((int)rawAllMix[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(12, Bmin + 4);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawAllMix[B].size() >= M) {\n                    books.push_back({B, \"all_mix\", rawAllMix[B]});\n                }\n            }\n        }\n    }\n\n    if (books.empty()) {\n        books.push_back({23, \"fallback\", rawPartAll[23]});\n    }\n\n    // --------------------------------------------------------\n    // Proxy search over (book, q), with improved q+eps-aware selection\n    // --------------------------------------------------------\n    struct Combo {\n        double proxy = -1.0;\n        int bookIdx = -1;\n        int q = -1;\n        vector<int> sel;\n    };\n    vector<Combo> combos;\n\n    for (int bi = 0; bi < (int)books.size(); bi++) {\n        int B = books[bi].B;\n        int qmax = 100 / B;\n        auto qs = q_candidates(qmax);\n\n        set<int> tried;\n        int localBestQ = 1;\n        double localBestProxy = -1.0;\n\n        auto try_q = [&](int q) {\n            if (q < 1 || q > qmax) return;\n            if (!tried.insert(q).second) return;\n\n            auto sel = select_code_indices_qaware(books[bi].pool, M, q, eps);\n            auto codes = materialize_selected(books[bi].pool, sel);\n            double pr = estimate_proxy_score(codes, q, eps, 1);\n\n            Combo c;\n            c.proxy = pr;\n            c.bookIdx = bi;\n            c.q = q;\n            c.sel = std::move(sel);\n            combos.push_back(std::move(c));\n\n            if (pr > localBestProxy) {\n                localBestProxy = pr;\n                localBestQ = q;\n            }\n        };\n\n        for (int q : qs) try_q(q);\n        for (int q = localBestQ - 2; q <= localBestQ + 2; q++) try_q(q);\n    }\n\n    sort(combos.begin(), combos.end(), [](const Combo& a, const Combo& b) {\n        if (a.proxy != b.proxy) return a.proxy > b.proxy;\n        if (a.bookIdx != b.bookIdx) return a.bookIdx < b.bookIdx;\n        return a.q < b.q;\n    });\n\n    // --------------------------------------------------------\n    // Actual refinement\n    // --------------------------------------------------------\n    struct Refined {\n        Codebook cb;\n        double est = -1.0;\n        int bookIdx = -1;\n        int q = -1;\n    };\n\n    vector<Refined> refined1;\n    int topProxy = min<int>(15, combos.size());\n    for (int i = 0; i < topProxy; i++) {\n        const auto& co = combos[i];\n        auto codes = materialize_selected(books[co.bookIdx].pool, co.sel);\n        Codebook cb = build_codebook(codes, co.q, eps);\n        double est = estimate_actual_score(\n            cb,\n            min(M, 24),\n            1,\n            0x9E3779B97F4A7C15ULL + 10007ULL * books[co.bookIdx].B + co.q * 911ULL + i * 1000003ULL\n        );\n        cb.estScore = est;\n        refined1.push_back({std::move(cb), est, co.bookIdx, co.q});\n    }\n\n    sort(refined1.begin(), refined1.end(), [](const Refined& a, const Refined& b) {\n        if (a.est != b.est) return a.est > b.est;\n        return a.cb.N < b.cb.N;\n    });\n\n    vector<Refined> refined2;\n    int top1 = min<int>(5, refined1.size());\n    for (int i = 0; i < top1; i++) {\n        auto x = std::move(refined1[i]);\n        x.est = estimate_actual_score(\n            x.cb,\n            min(M, 36),\n            2,\n            0xD1B54A32D192ED03ULL + 20011ULL * x.bookIdx + x.q * 1777ULL + i\n        );\n        x.cb.estScore = x.est;\n        refined2.push_back(std::move(x));\n    }\n\n    sort(refined2.begin(), refined2.end(), [](const Refined& a, const Refined& b) {\n        if (a.est != b.est) return a.est > b.est;\n        return a.cb.N < b.cb.N;\n    });\n\n    vector<Refined> refined3;\n    int top2 = min<int>(2, refined2.size());\n    for (int i = 0; i < top2; i++) {\n        auto x = std::move(refined2[i]);\n        x.est = estimate_actual_score(\n            x.cb,\n            min(M, 50),\n            3,\n            0x94D049BB133111EBULL + 30029ULL * x.bookIdx + x.q * 733ULL + i\n        );\n        x.cb.estScore = x.est;\n        refined3.push_back(std::move(x));\n    }\n\n    Codebook bestCB;\n    double bestRobust = -1.0;\n    if (!refined3.empty()) {\n        sort(refined3.begin(), refined3.end(), [](const Refined& a, const Refined& b) {\n            if (a.est != b.est) return a.est > b.est;\n            return a.cb.N < b.cb.N;\n        });\n        bestCB = std::move(refined3[0].cb);\n        bestRobust = refined3[0].est;\n    } else if (!refined2.empty()) {\n        bestCB = std::move(refined2[0].cb);\n        bestRobust = refined2[0].est;\n    } else if (!refined1.empty()) {\n        bestCB = std::move(refined1[0].cb);\n        bestRobust = refined1[0].est;\n    } else {\n        auto sel = select_code_indices_qaware(books[0].pool, M, 1, eps);\n        auto codes = materialize_selected(books[0].pool, sel);\n        bestCB = build_codebook(codes, 1, eps);\n        bestRobust = estimate_actual_score(bestCB, min(M, 20), 1, 1234567);\n        bestCB.estScore = bestRobust;\n    }\n\n    bool useSmall = false;\n    if (hasSmall && bestSmall.estScore > bestRobust) {\n        useSmall = true;\n    }\n\n    // --------------------------------------------------------\n    // Output chosen codebook\n    // --------------------------------------------------------\n    int N = useSmall ? bestSmall.N : bestCB.N;\n    cout << N << '\\n';\n    if (useSmall) {\n        for (int i = 0; i < M; i++) cout << bestSmall.graphStrs[i] << '\\n';\n    } else {\n        for (int i = 0; i < M; i++) cout << bestCB.graphStrs[i] << '\\n';\n    }\n    cout.flush();\n\n    // --------------------------------------------------------\n    // Query processing\n    // --------------------------------------------------------\n    if (useSmall) {\n        for (int q = 0; q < 100; q++) {\n            string H;\n            cin >> H;\n            uint16_t mask = 0;\n            for (int i = 0; i < bestSmall.E; i++) {\n                if (H[i] == '1') mask |= (uint16_t(1) << i);\n            }\n            int ans = decode_small(bestSmall, mask);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        static unsigned char adj[MAXN][MAXN];\n        for (int query = 0; query < 100; query++) {\n            string H;\n            cin >> H;\n            int pos = 0;\n            for (int i = 0; i < bestCB.N; i++) adj[i][i] = 0;\n            for (int i = 0; i < bestCB.N; i++) {\n                for (int j = i + 1; j < bestCB.N; j++) {\n                    unsigned char bit = (unsigned char)(H[pos++] - '0');\n                    adj[i][j] = adj[j][i] = bit;\n                }\n            }\n            int ans = decode_codebook(bestCB, adj);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x += 0x9e3779b97f4a7c15ull;\n        uint64_t z = x;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& a) {\n        for (int i = (int)a.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(a[i], a[j]);\n        }\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n    double mx, my;\n};\n\nstruct Adj {\n    int to, eid;\n};\n\nstruct PairW {\n    int a, b;\n    double w;\n};\n\nstruct State {\n    vector<int> day;       // size M\n    vector<int> cnt;       // size D\n    vector<double> load;   // normalized importance load per day\n    vector<double> same;   // size M*D, same[e*D+d] = conflict sum if e put on d\n};\n\nclass Solver {\n    static constexpr ll INF = (1LL << 60);\n    static constexpr ll UNREACH = 1000000000LL;\n    static constexpr double PI = 3.14159265358979323846;\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Adj>> g;\n    vector<pair<int,int>> pos;\n    vector<vector<int>> incident;\n    vector<int> degv;\n\n    double centroidX = 0.0, centroidY = 0.0;\n\n    vector<int> sources;\n    int S = 0;\n    vector<vector<ll>> baseDist; // S x N\n\n    vector<double> imp, impN;\n    vector<PairW> conflicts;\n    vector<vector<pair<int,double>>> neigh;\n    vector<double> neighSum;\n    double targetCnt = 0.0;\n    double targetLoad = 0.0;\n\n    chrono::steady_clock::time_point start_time;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    inline double& SAME(State& st, int e, int d) {\n        return st.same[(size_t)e * D + d];\n    }\n    inline double SAMEC(const State& st, int e, int d) const {\n        return st.same[(size_t)e * D + d];\n    }\n\n    void dijkstra_internal(int src, int banDay, const vector<int>& day,\n                           vector<ll>& dist,\n                           vector<int>* parentV = nullptr,\n                           vector<int>* parentE = nullptr) {\n        dist.assign(N, INF);\n        if (parentV) parentV->assign(N, -1);\n        if (parentE) parentE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n\n            for (const auto& a : g[v]) {\n                if (banDay >= 0 && day[a.eid] == banDay) continue;\n                int to = a.to;\n                ll nd = cd + edges[a.eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parentV) (*parentV)[to] = v;\n                    if (parentE) (*parentE)[to] = a.eid;\n                    pq.push({nd, to});\n                } else if (parentV && nd == dist[to]) {\n                    if ((*parentE)[to] == -1 || a.eid < (*parentE)[to]) {\n                        (*parentV)[to] = v;\n                        (*parentE)[to] = a.eid;\n                    }\n                }\n            }\n        }\n    }\n\n    void choose_sources() {\n        S = min(12, N);\n\n        // first source near centroid\n        int first = 0;\n        double best = 1e100;\n        for (int i = 0; i < N; ++i) {\n            double dx = pos[i].first - centroidX;\n            double dy = pos[i].second - centroidY;\n            double d2 = dx * dx + dy * dy;\n            if (d2 < best) {\n                best = d2;\n                first = i;\n            }\n        }\n\n        sources.clear();\n        vector<double> minD2(N, 1e100);\n\n        int cur = first;\n        for (int t = 0; t < S; ++t) {\n            sources.push_back(cur);\n            for (int i = 0; i < N; ++i) {\n                double dx = pos[i].first - pos[cur].first;\n                double dy = pos[i].second - pos[cur].second;\n                double d2 = dx * dx + dy * dy;\n                if (d2 < minD2[i]) minD2[i] = d2;\n            }\n            int nxt = -1;\n            double farv = -1.0;\n            for (int i = 0; i < N; ++i) {\n                bool used = false;\n                for (int s : sources) if (s == i) { used = true; break; }\n                if (used) continue;\n                if (minD2[i] > farv) {\n                    farv = minD2[i];\n                    nxt = i;\n                }\n            }\n            if (nxt == -1) break;\n            cur = nxt;\n        }\n        S = (int)sources.size();\n    }\n\n    void compute_importance() {\n        choose_sources();\n        baseDist.assign(S, vector<ll>(N));\n\n        double avgw = 0.0;\n        for (auto& e : edges) avgw += e.w;\n        avgw /= M;\n\n        vector<double> usage(M, 0.0);\n        vector<ll> dist;\n        vector<int> pv, pe;\n\n        vector<int> emptyDay; // banDay < 0 => ignored\n\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, -1, emptyDay, dist, &pv, &pe);\n            baseDist[si] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sub(N, 1);\n            for (int v : ord) {\n                if (v == src) continue;\n                if (pe[v] != -1) {\n                    usage[pe[v]] += sub[v];\n                    sub[pv[v]] += sub[v];\n                }\n            }\n        }\n\n        imp.assign(M, 1.0);\n        for (int e = 0; e < M; ++e) {\n            double wf = sqrt((double)edges[e].w / avgw);\n            imp[e] = sqrt(1.0 + usage[e]) * (0.7 + 0.3 * wf);\n        }\n\n        double avgImp = 0.0;\n        for (double x : imp) avgImp += x;\n        avgImp /= M;\n\n        impN.resize(M);\n        for (int e = 0; e < M; ++e) impN[e] = imp[e] / avgImp;\n\n        targetCnt = (double)M / D;\n        double sumImpN = 0.0;\n        for (double x : impN) sumImpN += x;\n        targetLoad = sumImpN / D;\n    }\n\n    void build_conflicts() {\n        struct Tmp {\n            int a, b;\n            double w;\n        };\n        vector<Tmp> tmp;\n        tmp.reserve(200000);\n\n        // strong conflicts for edges sharing a vertex\n        for (int v = 0; v < N; ++v) {\n            auto& inc = incident[v];\n            int deg = (int)inc.size();\n            double lowFactor = 1.0 + 0.8 * max(0, 5 - deg); // deg2 -> strong\n            for (int i = 0; i < deg; ++i) {\n                for (int j = i + 1; j < deg; ++j) {\n                    int a = inc[i], b = inc[j];\n                    if (a > b) swap(a, b);\n                    double w = 40.0 * lowFactor * (0.7 + 0.15 * (impN[a] + impN[b]));\n                    tmp.push_back({a, b, w});\n                }\n            }\n        }\n\n        // medium conflicts for spatially close edges\n        const double R = 110.0;\n        const double R2 = R * R;\n        const int CELL = 110;\n        const int G = 1000 / CELL + 4;\n\n        auto cell_id = [&](int x, int y) {\n            return x * G + y;\n        };\n\n        vector<vector<int>> cells(G * G);\n        for (int e = 0; e < M; ++e) {\n            int cx = min(G - 1, max(0, (int)(edges[e].mx / CELL)));\n            int cy = min(G - 1, max(0, (int)(edges[e].my / CELL)));\n            cells[cell_id(cx, cy)].push_back(e);\n        }\n\n        auto share_vertex = [&](int a, int b) -> bool {\n            const auto& A = edges[a];\n            const auto& B = edges[b];\n            return A.u == B.u || A.u == B.v || A.v == B.u || A.v == B.v;\n        };\n\n        for (int x = 0; x < G; ++x) {\n            for (int y = 0; y < G; ++y) {\n                int id1 = cell_id(x, y);\n                for (int nx = max(0, x - 1); nx <= min(G - 1, x + 1); ++nx) {\n                    for (int ny = max(0, y - 1); ny <= min(G - 1, y + 1); ++ny) {\n                        if (nx < x || (nx == x && ny < y)) continue;\n                        int id2 = cell_id(nx, ny);\n                        const auto& c1 = cells[id1];\n                        const auto& c2 = cells[id2];\n                        if (id1 == id2) {\n                            for (int i = 0; i < (int)c1.size(); ++i) {\n                                for (int j = i + 1; j < (int)c1.size(); ++j) {\n                                    int a = c1[i], b = c1[j];\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        if (a > b) swap(a, b);\n                                        tmp.push_back({a, b, w});\n                                    }\n                                }\n                            }\n                        } else {\n                            for (int a : c1) {\n                                for (int b : c2) {\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        int x1 = a, x2 = b;\n                                        if (x1 > x2) swap(x1, x2);\n                                        tmp.push_back({x1, x2, w});\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        sort(tmp.begin(), tmp.end(), [&](const Tmp& p, const Tmp& q) {\n            if (p.a != q.a) return p.a < q.a;\n            return p.b < q.b;\n        });\n\n        conflicts.clear();\n        for (int i = 0; i < (int)tmp.size(); ) {\n            int j = i + 1;\n            double sw = tmp[i].w;\n            while (j < (int)tmp.size() && tmp[j].a == tmp[i].a && tmp[j].b == tmp[i].b) {\n                sw += tmp[j].w;\n                ++j;\n            }\n            conflicts.push_back({tmp[i].a, tmp[i].b, sw});\n            i = j;\n        }\n\n        neigh.assign(M, {});\n        neighSum.assign(M, 0.0);\n        for (auto& p : conflicts) {\n            neigh[p.a].push_back({p.b, p.w});\n            neigh[p.b].push_back({p.a, p.w});\n            neighSum[p.a] += p.w;\n            neighSum[p.b] += p.w;\n        }\n    }\n\n    inline double add_cost(int cnt, double load, double ie, double lc, double li) const {\n        double dc = (cnt + 1 - targetCnt) * (cnt + 1 - targetCnt) - (cnt - targetCnt) * (cnt - targetCnt);\n        double dl = (load + ie - targetLoad) * (load + ie - targetLoad) - (load - targetLoad) * (load - targetLoad);\n        return lc * dc + li * dl;\n    }\n\n    inline double move_delta_proxy(const State& st, int e, int b, double lc, double li) const {\n        int a = st.day[e];\n        if (a == b) return 0.0;\n        if (st.cnt[b] >= K) return 1e100;\n\n        double pairDelta = SAMEC(st, e, b) - SAMEC(st, e, a);\n\n        double dc =\n            (st.cnt[a] - 1 - targetCnt) * (st.cnt[a] - 1 - targetCnt) +\n            (st.cnt[b] + 1 - targetCnt) * (st.cnt[b] + 1 - targetCnt) -\n            (st.cnt[a] - targetCnt) * (st.cnt[a] - targetCnt) -\n            (st.cnt[b] - targetCnt) * (st.cnt[b] - targetCnt);\n\n        double ie = impN[e];\n        double dl =\n            (st.load[a] - ie - targetLoad) * (st.load[a] - ie - targetLoad) +\n            (st.load[b] + ie - targetLoad) * (st.load[b] + ie - targetLoad) -\n            (st.load[a] - targetLoad) * (st.load[a] - targetLoad) -\n            (st.load[b] - targetLoad) * (st.load[b] - targetLoad);\n\n        return pairDelta + lc * dc + li * dl;\n    }\n\n    void apply_move(State& st, int e, int b) {\n        int a = st.day[e];\n        if (a == b) return;\n        st.cnt[a]--;\n        st.cnt[b]++;\n        st.load[a] -= impN[e];\n        st.load[b] += impN[e];\n\n        for (auto [f, w] : neigh[e]) {\n            SAME(st, f, a) -= w;\n            SAME(st, f, b) += w;\n        }\n        st.day[e] = b;\n    }\n\n    State build_state(const vector<int>& day) {\n        State st;\n        st.day = day;\n        st.cnt.assign(D, 0);\n        st.load.assign(D, 0.0);\n\n        for (int e = 0; e < M; ++e) {\n            st.cnt[day[e]]++;\n            st.load[day[e]] += impN[e];\n        }\n\n        st.same.assign((size_t)M * D, 0.0);\n        for (auto& p : conflicts) {\n            SAME(st, p.a, st.day[p.b]) += p.w;\n            SAME(st, p.b, st.day[p.a]) += p.w;\n        }\n        return st;\n    }\n\n    vector<int> construct_initial(int type, RNG& rng, double lc, double li) {\n        vector<int> order;\n        order.reserve(M);\n        vector<int> pref(M, -1);\n\n        if (type == 0) {\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = neighSum[e] + 5.0 * impN[e] + 3.0 * rng.next_double();\n                arr.push_back({-key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n        } else if (type == 1) {\n            double th = rng.next_double() * 2.0 * PI;\n            double cs = cos(th), sn = sin(th);\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = edges[e].mx * cs + edges[e].my * sn + 1e-6 * rng.next_double();\n                arr.push_back({key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        } else {\n            double shift = rng.next_double() * 2.0 * PI;\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double ang = atan2(edges[e].my - centroidY, edges[e].mx - centroidX) - shift;\n                while (ang < 0) ang += 2.0 * PI;\n                while (ang >= 2.0 * PI) ang -= 2.0 * PI;\n                arr.push_back({ang + 1e-6 * rng.next_double(), e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        }\n\n        double prefPenalty = 8.0 + 6.0 * rng.next_double();\n\n        vector<int> day(M, -1);\n        vector<int> cnt(D, 0);\n        vector<double> load(D, 0.0);\n        array<double, 32> tmpConf{};\n\n        for (int e : order) {\n            for (int d = 0; d < D; ++d) tmpConf[d] = 0.0;\n            for (auto [f, w] : neigh[e]) {\n                int df = day[f];\n                if (df != -1) tmpConf[df] += w;\n            }\n\n            int bestd = -1;\n            double bestScore = 1e100;\n            int offset = rng.next_int(D);\n\n            for (int zz = 0; zz < D; ++zz) {\n                int d = (offset + zz) % D;\n                if (cnt[d] >= K) continue;\n                double sc = tmpConf[d] + add_cost(cnt[d], load[d], impN[e], lc, li);\n                if (pref[e] != -1 && d != pref[e]) sc += prefPenalty;\n                sc += 1e-7 * rng.next_double();\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestd = d;\n                }\n            }\n\n            if (bestd == -1) {\n                // fallback, should not happen\n                bestd = 0;\n                while (cnt[bestd] >= K) ++bestd;\n            }\n\n            day[e] = bestd;\n            cnt[bestd]++;\n            load[bestd] += impN[e];\n        }\n\n        return day;\n    }\n\n    void proxy_improve(State& st, RNG& rng, double lc, double li) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < 8; ++pass) {\n            rng.shuffle_vec(ord);\n            int moved = 0;\n\n            for (int e : ord) {\n                int a = st.day[e];\n                int bestd = a;\n                double bestDelta = -1e-9;\n\n                int offset = rng.next_int(D);\n                for (int zz = 0; zz < D; ++zz) {\n                    int d = (offset + zz) % D;\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                    }\n                }\n\n                if (bestd != a) {\n                    apply_move(st, e, bestd);\n                    moved++;\n                }\n            }\n\n            if (moved == 0) break;\n            if (elapsed() > 4.5) break;\n        }\n    }\n\n    ll eval_day_cost(int banDay, const vector<int>& day) {\n        ll res = 0;\n        vector<ll> dist;\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, banDay, day, dist, nullptr, nullptr);\n            const auto& bd = baseDist[si];\n            for (int v = 0; v < N; ++v) {\n                if (v == src) continue;\n                ll nd = (dist[v] >= INF / 2 ? UNREACH : dist[v]);\n                res += nd - bd[v];\n            }\n        }\n        return res;\n    }\n\n    ll eval_schedule(const vector<int>& day, const vector<int>& cnt, vector<ll>& dayCost) {\n        dayCost.assign(D, 0);\n        ll total = 0;\n        for (int d = 0; d < D; ++d) {\n            if (cnt[d] == 0) continue;\n            dayCost[d] = eval_day_cost(d, day);\n            total += dayCost[d];\n        }\n        return total;\n    }\n\n    void actual_refine(vector<int>& bestDay, double lc, double li) {\n        State st = build_state(bestDay);\n        vector<ll> dayCost;\n        ll curScore = eval_schedule(st.day, st.cnt, dayCost);\n\n        int accepted = 0;\n        while (elapsed() < 5.45 && accepted < 25) {\n            vector<int> worstOrd(D);\n            iota(worstOrd.begin(), worstOrd.end(), 0);\n            sort(worstOrd.begin(), worstOrd.end(), [&](int a, int b) {\n                return dayCost[a] > dayCost[b];\n            });\n\n            int takeDays = min(3, D);\n            array<int, 32> isTop{};\n            for (int i = 0; i < takeDays; ++i) isTop[worstOrd[i]] = 1;\n\n            vector<pair<double,int>> candEdges;\n            candEdges.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                int d = st.day[e];\n                if (!isTop[d]) continue;\n                double score = SAMEC(st, e, d) + 4.0 * impN[e];\n                candEdges.push_back({-score, e});\n            }\n\n            if (candEdges.empty()) break;\n            sort(candEdges.begin(), candEdges.end());\n            if ((int)candEdges.size() > 50) candEdges.resize(50);\n\n            vector<int> lowOrd(D);\n            iota(lowOrd.begin(), lowOrd.end(), 0);\n            sort(lowOrd.begin(), lowOrd.end(), [&](int a, int b) {\n                return dayCost[a] < dayCost[b];\n            });\n\n            bool moved = false;\n\n            for (auto [negScore, e] : candEdges) {\n                if (elapsed() > 5.45) break;\n\n                int a = st.day[e];\n                vector<pair<double,int>> pd;\n                pd.reserve(D);\n\n                for (int d = 0; d < D; ++d) {\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    pd.push_back({delta, d});\n                }\n                if (pd.empty()) continue;\n\n                sort(pd.begin(), pd.end());\n                vector<int> candDays;\n                for (int i = 0; i < (int)pd.size() && i < 4; ++i) candDays.push_back(pd[i].second);\n                for (int i = 0; i < min(2, D); ++i) {\n                    int d = lowOrd[i];\n                    if (d == a || st.cnt[d] >= K) continue;\n                    bool found = false;\n                    for (int x : candDays) if (x == d) found = true;\n                    if (!found) candDays.push_back(d);\n                }\n\n                ll bestDelta = 0;\n                int bestd = -1;\n                ll bestA = 0, bestB = 0;\n\n                int old = st.day[e];\n                for (int d : candDays) {\n                    st.day[e] = d;\n                    ll na = eval_day_cost(a, st.day);\n                    ll nb = eval_day_cost(d, st.day);\n                    ll delta = (na + nb) - (dayCost[a] + dayCost[d]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                        bestA = na;\n                        bestB = nb;\n                    }\n                }\n                st.day[e] = old;\n\n                if (bestd != -1) {\n                    apply_move(st, e, bestd);\n                    dayCost[a] = bestA;\n                    dayCost[bestd] = bestB;\n                    curScore += bestDelta;\n                    accepted++;\n                    moved = true;\n                    break;\n                }\n            }\n\n            if (!moved) break;\n        }\n\n        bestDay = st.day;\n        (void)curScore;\n    }\n\npublic:\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(N, {});\n        degv.assign(N, 0);\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            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            degv[u]++;\n            degv[v]++;\n        }\n\n        pos.resize(N);\n        for (int i = 0; i < N; ++i) {\n            cin >> pos[i].first >> pos[i].second;\n            centroidX += pos[i].first;\n            centroidY += pos[i].second;\n        }\n        centroidX /= N;\n        centroidY /= N;\n\n        for (int i = 0; i < M; ++i) {\n            edges[i].mx = 0.5 * (pos[edges[i].u].first + pos[edges[i].v].first);\n            edges[i].my = 0.5 * (pos[edges[i].u].second + pos[edges[i].v].second);\n        }\n\n        compute_importance();\n        build_conflicts();\n\n        uint64_t seedBase = 1469598103934665603ull;\n        seedBase ^= (uint64_t)N + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)M + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)D + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)K + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n\n        vector<int> bestDay;\n        ll bestScore = (1LL << 62);\n        double bestLc = 4.5, bestLi = 2.0;\n\n        int runs = 0;\n        while (elapsed() < 3.8 && runs < 12) {\n            RNG rng(seedBase + 1000003ull * (uint64_t)runs + 1234567ull);\n\n            double lc = 3.5 + 2.5 * rng.next_double();\n            double li = 1.5 + 2.0 * rng.next_double();\n\n            int type = runs % 3;\n            vector<int> initDay = construct_initial(type, rng, lc, li);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, lc, li);\n\n            vector<ll> dayCost;\n            ll sc = eval_schedule(st.day, st.cnt, dayCost);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestDay = st.day;\n                bestLc = lc;\n                bestLi = li;\n            }\n            runs++;\n        }\n\n        if (bestDay.empty()) {\n            RNG rng(seedBase);\n            vector<int> initDay = construct_initial(0, rng, 4.5, 2.0);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, 4.5, 2.0);\n            bestDay = st.day;\n        }\n\n        actual_refine(bestDay, bestLc, bestLi);\n\n        for (int i = 0; i < M; ++i) {\n            if (i) cout << ' ';\n            cout << bestDay[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\nstatic constexpr int MAXD = 14;\nstatic constexpr int MAXN = MAXD * MAXD * MAXD;\nstatic constexpr int NEG_INF = -1000000000;\n\nint D, Ncells;\n\nstring fstr[2][MAXD], rstr[2][MAXD];\nuint16_t actXMask[2][MAXD], actYMask[2][MAXD];\nvector<int> actXList[2][MAXD], actYList[2][MAXD];\nuint8_t activeCell[2][MAXD][MAXD][MAXD];\n\nchrono::steady_clock::time_point g_start;\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\ninline void decode3(int id, int &x, int &y, int &z) {\n    x = id / (D * D);\n    int rem = id % (D * D);\n    y = rem / D;\n    z = rem % D;\n}\ninline int popcnt16(uint16_t x) {\n    return __builtin_popcount((unsigned)x);\n}\n\nuint32_t tiny_hash(uint32_t x) {\n    x ^= x >> 16;\n    x *= 0x7feb352dU;\n    x ^= x >> 15;\n    x *= 0x846ca68bU;\n    x ^= x >> 16;\n    return x;\n}\ninline int tiny_noise(int seed, int x, int y, int z) {\n    uint32_t v = (uint32_t)seed * 1000003u\n               ^ (uint32_t)(x + 1) * 911382323u\n               ^ (uint32_t)(y + 1) * 972663749u\n               ^ (uint32_t)(z + 1) * 19260817u;\n    return (int)(tiny_hash(v) & 31u);\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nstruct Comp {\n    vector<int> cells;\n    int vol = 0;\n};\n\nstruct LineSeg {\n    int axis; // 0:x, 1:y, 2:z\n    int x, y, z;\n    int len;\n};\n\nstruct ShapeComp {\n    vector<int> cells;\n    int vol = 0;\n    string sig;\n};\n\nstruct LineSegCmp {\n    bool operator()(const LineSeg& a, const LineSeg& b) const {\n        if (a.len != b.len) return a.len < b.len;\n        if (a.axis != b.axis) return a.axis > b.axis;\n        if (a.x != b.x) return a.x > b.x;\n        if (a.y != b.y) return a.y > b.y;\n        return a.z > b.z;\n    }\n};\n\nstruct Candidate {\n    array<uint8_t, MAXN> occ{};\n    vector<ShapeComp> comps;\n};\n\nstruct CoreInfo {\n    vector<char> keep;\n    long double scoreCore = 0.0L;\n    uint16_t covX[MAXD]{};\n    uint16_t covY[MAXD]{};\n    uint16_t coreRow[MAXD][MAXD]{}; // bitmask of y for each (z,x)\n    int remVol[2]{};\n};\n\nstruct Param {\n    int dir;   // +1 forward, -1 backward\n    int alpha; // continuation reward\n    int beta;  // future run reward\n    int seed;  // tie-break diversity\n};\n\nstruct PairPlan {\n    long double extraScore = 0.0L;\n    vector<pair<int,int>> matchedExtra;\n\n    // residual decomposition per side:\n    // mode=0 => global axis, mode=1 => per-component best axis\n    int mode1 = 0, mode2 = 0;\n    int axis1 = 2, axis2 = 2;\n    vector<int> compAxis1, compAxis2;\n};\n\nstruct EvalResult {\n    bool ok = false;\n    long double score = 1e100L;\n    Candidate c1, c2;\n    PairPlan plan;\n};\n\nstruct State {\n    bool ok = false;\n    long double score = 1e100L;\n    CoreInfo core;\n    Candidate c1, c2;\n    PairPlan plan;\n};\n\nvector<Comp> commonComps;\nvector<array<int,3>> rotPerm;\nvector<array<int,3>> rotSign;\n\nint runF[2][MAXD][MAXD][MAXD + 1];\nint runB[2][MAXD][MAXD][MAXD];\n\nint perm_parity(const array<int,3>& p) {\n    int inv = 0;\n    for (int i = 0; i < 3; i++) for (int j = i + 1; j < 3; j++) {\n        if (p[i] > p[j]) inv++;\n    }\n    return (inv % 2 == 0 ? 1 : -1);\n}\n\nvoid init_rotations() {\n    rotPerm.clear();\n    rotSign.clear();\n    array<int,3> p = {0,1,2};\n    sort(p.begin(), p.end());\n    do {\n        int par = perm_parity(p);\n        for (int sx : {-1, 1}) for (int sy : {-1, 1}) for (int sz : {-1, 1}) {\n            if (par * sx * sy * sz == 1) {\n                rotPerm.push_back(p);\n                rotSign.push_back({sx, sy, sz});\n            }\n        }\n    } while (next_permutation(p.begin(), p.end()));\n}\n\nstring canonical_signature(const vector<int>& cells) {\n    vector<array<int,3>> coords;\n    coords.reserve(cells.size());\n    for (int id : cells) {\n        int x, y, z;\n        decode3(id, x, y, z);\n        coords.push_back({x, y, z});\n    }\n\n    string best;\n    bool first = true;\n\n    for (int r = 0; r < (int)rotPerm.size(); r++) {\n        vector<array<int,3>> t;\n        t.reserve(coords.size());\n        int mn0 = INT_MAX, mn1 = INT_MAX, mn2 = INT_MAX;\n\n        const auto& p = rotPerm[r];\n        const auto& s = rotSign[r];\n\n        for (auto &c : coords) {\n            int v[3] = {c[0], c[1], c[2]};\n            int a = s[0] * v[p[0]];\n            int b = s[1] * v[p[1]];\n            int cc = s[2] * v[p[2]];\n            mn0 = min(mn0, a);\n            mn1 = min(mn1, b);\n            mn2 = min(mn2, cc);\n            t.push_back({a, b, cc});\n        }\n\n        for (auto &q : t) {\n            q[0] -= mn0;\n            q[1] -= mn1;\n            q[2] -= mn2;\n        }\n        sort(t.begin(), t.end());\n\n        string sig;\n        sig.reserve(t.size() * 3);\n        for (auto &q : t) {\n            sig.push_back((char)q[0]);\n            sig.push_back((char)q[1]);\n            sig.push_back((char)q[2]);\n        }\n        if (first || sig < best) {\n            best = std::move(sig);\n            first = false;\n        }\n    }\n    return best;\n}\n\nvoid extract_shape_components(const array<uint8_t, MAXN>& occ, vector<ShapeComp>& out) {\n    out.clear();\n    vector<uint8_t> vis(Ncells, 0);\n    const int dx[6] = {1, -1, 0, 0, 0, 0};\n    const int dy[6] = {0, 0, 1, -1, 0, 0};\n    const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    for (int s = 0; s < Ncells; s++) {\n        if (!occ[s] || vis[s]) continue;\n        queue<int> q;\n        q.push(s);\n        vis[s] = 1;\n        ShapeComp c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (occ[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        c.sig = canonical_signature(c.cells);\n        out.push_back(std::move(c));\n    }\n}\n\nvoid build_full_common_components() {\n    vector<uint8_t> common(Ncells, 0);\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (activeCell[0][x][y][z] && activeCell[1][x][y][z]) {\n            common[idx3(x, y, z)] = 1;\n        }\n    }\n\n    vector<uint8_t> vis(Ncells, 0);\n    const int dx[6] = {1, -1, 0, 0, 0, 0};\n    const int dy[6] = {0, 0, 1, -1, 0, 0};\n    const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    for (int s = 0; s < Ncells; s++) {\n        if (!common[s] || vis[s]) continue;\n        queue<int> q;\n        q.push(s);\n        vis[s] = 1;\n        Comp c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (common[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        commonComps.push_back(std::move(c));\n    }\n}\n\nCoreInfo build_core_from_keep(const vector<char>& keep) {\n    CoreInfo core;\n    core.keep = keep;\n    for (int z = 0; z < D; z++) {\n        core.covX[z] = 0;\n        core.covY[z] = 0;\n        for (int x = 0; x < D; x++) core.coreRow[z][x] = 0;\n    }\n\n    for (int cid = 0; cid < (int)commonComps.size(); cid++) {\n        if (!keep[cid]) continue;\n        core.scoreCore += 1.0L / (long double)commonComps[cid].vol;\n        for (int id : commonComps[cid].cells) {\n            int x, y, z;\n            decode3(id, x, y, z);\n            core.covX[z] |= (uint16_t(1) << x);\n            core.covY[z] |= (uint16_t(1) << y);\n            core.coreRow[z][x] |= (uint16_t(1) << y);\n        }\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        int vol = 0;\n        for (int z = 0; z < D; z++) {\n            int ur = popcnt16(actXMask[obj][z] & ~core.covX[z]);\n            int uc = popcnt16(actYMask[obj][z] & ~core.covY[z]);\n            vol += max(ur, uc);\n        }\n        core.remVol[obj] = vol;\n    }\n    return core;\n}\n\nCoreInfo build_core_by_threshold(int threshold) {\n    vector<char> keep(commonComps.size(), 0);\n    for (int i = 0; i < (int)commonComps.size(); i++) {\n        if (commonComps[i].vol > threshold) keep[i] = 1;\n    }\n    return build_core_from_keep(keep);\n}\n\nvoid build_runs(const CoreInfo& core) {\n    for (int obj = 0; obj < 2; obj++) {\n        for (int x = 0; x < D; x++) {\n            for (int y = 0; y < D; y++) {\n                runF[obj][x][y][D] = 0;\n                for (int z = D - 1; z >= 0; z--) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runF[obj][x][y][z] = avail ? 1 + runF[obj][x][y][z + 1] : 0;\n                }\n                for (int z = 0; z < D; z++) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runB[obj][x][y][z] = avail ? 1 + (z ? runB[obj][x][y][z - 1] : 0) : 0;\n                }\n            }\n        }\n    }\n}\n\nvector<int> solve_dp_assignment(\n    const vector<int>& domain,\n    const vector<int>& choices,\n    const vector<int>& mandatory,\n    int w[MAXD][MAXD]\n) {\n    int p = (int)domain.size();\n    int q = (int)choices.size();\n    int m = (int)mandatory.size();\n\n    vector<int> ret(p, 0);\n    if (p == 0) return ret;\n\n    int pos[MAXD];\n    for (int i = 0; i < MAXD; i++) pos[i] = -1;\n    for (int i = 0; i < m; i++) pos[mandatory[i]] = i;\n\n    int bitOfChoice[MAXD];\n    for (int j = 0; j < q; j++) {\n        bitOfChoice[j] = (pos[choices[j]] == -1 ? 0 : (1 << pos[choices[j]]));\n    }\n\n    int S = 1 << m;\n    static int dp[1 << MAXD], ndp[1 << MAXD];\n    static uint16_t parentMask[MAXD + 1][1 << MAXD];\n    static int8_t parentChoice[MAXD + 1][1 << MAXD];\n\n    for (int mask = 0; mask < S; mask++) dp[mask] = NEG_INF;\n    dp[0] = 0;\n\n    for (int i = 0; i < p; i++) {\n        for (int mask = 0; mask < S; mask++) ndp[mask] = NEG_INF;\n        for (int mask = 0; mask < S; mask++) if (dp[mask] > NEG_INF / 2) {\n            for (int j = 0; j < q; j++) {\n                int ww = w[i][j];\n                if (ww <= NEG_INF / 2) continue;\n                int nmask = mask | bitOfChoice[j];\n                int val = dp[mask] + ww;\n                if (val > ndp[nmask]) {\n                    ndp[nmask] = val;\n                    parentMask[i + 1][nmask] = (uint16_t)mask;\n                    parentChoice[i + 1][nmask] = (int8_t)j;\n                }\n            }\n        }\n        for (int mask = 0; mask < S; mask++) dp[mask] = ndp[mask];\n    }\n\n    int full = S - 1;\n    if (dp[full] <= NEG_INF / 2) {\n        for (int i = 0; i < p; i++) {\n            int bestj = 0, bestv = NEG_INF;\n            for (int j = 0; j < q; j++) {\n                if (w[i][j] > bestv) {\n                    bestv = w[i][j];\n                    bestj = j;\n                }\n            }\n            ret[i] = bestj;\n        }\n        return ret;\n    }\n\n    int mask = full;\n    for (int i = p; i >= 1; i--) {\n        int j = parentChoice[i][mask];\n        ret[i - 1] = j;\n        mask = parentMask[i][mask];\n    }\n    return ret;\n}\n\nCandidate build_candidate_dp(\n    int obj,\n    const CoreInfo& core,\n    const Param& prm,\n    const array<uint8_t, MAXN>* prefOcc = nullptr,\n    int overlapBonus = 0\n) {\n    Candidate cand;\n    cand.occ.fill(0);\n\n    uint16_t prevRow[MAXD]{};\n    uint16_t curRow[MAXD]{};\n\n    int zStart = (prm.dir == 1 ? 0 : D - 1);\n    int zEnd   = (prm.dir == 1 ? D : -1);\n    int zStep  = (prm.dir == 1 ? 1 : -1);\n\n    for (int z = zStart; z != zEnd; z += zStep) {\n        for (int x = 0; x < D; x++) curRow[x] = 0;\n\n        vector<int> uncRows, uncCols;\n        uint16_t rowMask = actXMask[obj][z] & ~core.covX[z];\n        uint16_t colMask = actYMask[obj][z] & ~core.covY[z];\n\n        for (int x : actXList[obj][z]) if ((rowMask >> x) & 1) uncRows.push_back(x);\n        for (int y : actYList[obj][z]) if ((colMask >> y) & 1) uncCols.push_back(y);\n\n        if (uncRows.empty() && uncCols.empty()) {\n            memcpy(prevRow, curRow, sizeof(prevRow));\n            continue;\n        }\n\n        int w[MAXD][MAXD];\n        for (int i = 0; i < MAXD; i++) for (int j = 0; j < MAXD; j++) w[i][j] = NEG_INF;\n\n        if ((int)uncRows.size() >= (int)uncCols.size()) {\n            const auto& domain = uncRows;\n            const auto& choices = actYList[obj][z];\n            const auto& mandatory = uncCols;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int y = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue;\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int ov = (prefOcc && (*prefOcc)[idx3(x, y, z)]) ? overlapBonus : 0;\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + ov + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                int y = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        } else {\n            const auto& domain = uncCols;\n            const auto& choices = actXList[obj][z];\n            const auto& mandatory = uncRows;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int x = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue;\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int ov = (prefOcc && (*prefOcc)[idx3(x, y, z)]) ? overlapBonus : 0;\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + ov + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                int x = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        }\n\n        memcpy(prevRow, curRow, sizeof(prevRow));\n    }\n\n    extract_shape_components(cand.occ, cand.comps);\n    return cand;\n}\n\nCandidate build_candidate_group_shift(int obj, const CoreInfo& core, bool revA, bool revB, int shift) {\n    Candidate cand;\n    cand.occ.fill(0);\n\n    for (int z = 0; z < D; z++) {\n        vector<int> uncRows, uncCols;\n        uint16_t rowMask = actXMask[obj][z] & ~core.covX[z];\n        uint16_t colMask = actYMask[obj][z] & ~core.covY[z];\n\n        for (int x : actXList[obj][z]) if ((rowMask >> x) & 1) uncRows.push_back(x);\n        for (int y : actYList[obj][z]) if ((colMask >> y) & 1) uncCols.push_back(y);\n\n        if (uncRows.empty() && uncCols.empty()) continue;\n\n        if ((int)uncRows.size() >= (int)uncCols.size()) {\n            vector<int> X = uncRows;\n            vector<int> Yreq = uncCols;\n            const auto& Yall = actYList[obj][z];\n\n            if (revA) reverse(X.begin(), X.end());\n            if (revB) reverse(Yreq.begin(), Yreq.end());\n            if (!Yreq.empty()) {\n                int s = shift % (int)Yreq.size();\n                rotate(Yreq.begin(), Yreq.begin() + s, Yreq.end());\n            }\n\n            if (Yreq.empty()) {\n                int y = Yall[shift % (int)Yall.size()];\n                for (int x : X) cand.occ[idx3(x, y, z)] = 1;\n            } else {\n                int p = (int)X.size(), k = (int)Yreq.size();\n                for (int g = 0; g < k; g++) {\n                    int l = (long long)g * p / k;\n                    int r = (long long)(g + 1) * p / k;\n                    int y = Yreq[g];\n                    for (int i = l; i < r; i++) cand.occ[idx3(X[i], y, z)] = 1;\n                }\n            }\n        } else {\n            vector<int> Y = uncCols;\n            vector<int> Xreq = uncRows;\n            const auto& Xall = actXList[obj][z];\n\n            if (revA) reverse(Y.begin(), Y.end());\n            if (revB) reverse(Xreq.begin(), Xreq.end());\n            if (!Xreq.empty()) {\n                int s = shift % (int)Xreq.size();\n                rotate(Xreq.begin(), Xreq.begin() + s, Xreq.end());\n            }\n\n            if (Xreq.empty()) {\n                int x = Xall[shift % (int)Xall.size()];\n                for (int y : Y) cand.occ[idx3(x, y, z)] = 1;\n            } else {\n                int p = (int)Y.size(), k = (int)Xreq.size();\n                for (int g = 0; g < k; g++) {\n                    int l = (long long)g * p / k;\n                    int r = (long long)(g + 1) * p / k;\n                    int x = Xreq[g];\n                    for (int i = l; i < r; i++) cand.occ[idx3(x, Y[i], z)] = 1;\n                }\n            }\n        }\n    }\n\n    extract_shape_components(cand.occ, cand.comps);\n    return cand;\n}\n\nvoid extract_segments_axis(const array<uint8_t, MAXN>& occ, int axis, vector<LineSeg>& segs) {\n    segs.clear();\n\n    if (axis == 0) {\n        for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n            int x = 0;\n            while (x < D) {\n                while (x < D && !occ[idx3(x, y, z)]) x++;\n                if (x == D) break;\n                int x0 = x;\n                while (x < D && occ[idx3(x, y, z)]) x++;\n                segs.push_back({0, x0, y, z, x - x0});\n            }\n        }\n    } else if (axis == 1) {\n        for (int x = 0; x < D; x++) for (int z = 0; z < D; z++) {\n            int y = 0;\n            while (y < D) {\n                while (y < D && !occ[idx3(x, y, z)]) y++;\n                if (y == D) break;\n                int y0 = y;\n                while (y < D && occ[idx3(x, y, z)]) y++;\n                segs.push_back({1, x, y0, z, y - y0});\n            }\n        }\n    } else {\n        for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) {\n            int z = 0;\n            while (z < D) {\n                while (z < D && !occ[idx3(x, y, z)]) z++;\n                if (z == D) break;\n                int z0 = z;\n                while (z < D && occ[idx3(x, y, z)]) z++;\n                segs.push_back({2, x, y, z0, z - z0});\n            }\n        }\n    }\n}\n\nstruct AxisDecomp {\n    int axis = 2;\n    vector<LineSeg> segs;\n    long long sumSq = -1;\n    int maxLen = -1;\n    int numSeg = 1e9;\n};\n\nvoid append_component_axis_segments(const ShapeComp& comp, int axis, vector<LineSeg>& out) {\n    static array<uint8_t, MAXN> mark;\n    int xmin = D, xmax = -1, ymin = D, ymax = -1, zmin = D, zmax = -1;\n    for (int id : comp.cells) {\n        mark[id] = 1;\n        int x, y, z;\n        decode3(id, x, y, z);\n        xmin = min(xmin, x); xmax = max(xmax, x);\n        ymin = min(ymin, y); ymax = max(ymax, y);\n        zmin = min(zmin, z); zmax = max(zmax, z);\n    }\n\n    if (axis == 0) {\n        for (int y = ymin; y <= ymax; y++) for (int z = zmin; z <= zmax; z++) {\n            int x = xmin;\n            while (x <= xmax) {\n                while (x <= xmax && !mark[idx3(x, y, z)]) x++;\n                if (x > xmax) break;\n                int x0 = x;\n                while (x <= xmax && mark[idx3(x, y, z)]) x++;\n                out.push_back({0, x0, y, z, x - x0});\n            }\n        }\n    } else if (axis == 1) {\n        for (int x = xmin; x <= xmax; x++) for (int z = zmin; z <= zmax; z++) {\n            int y = ymin;\n            while (y <= ymax) {\n                while (y <= ymax && !mark[idx3(x, y, z)]) y++;\n                if (y > ymax) break;\n                int y0 = y;\n                while (y <= ymax && mark[idx3(x, y, z)]) y++;\n                out.push_back({1, x, y0, z, y - y0});\n            }\n        }\n    } else {\n        for (int x = xmin; x <= xmax; x++) for (int y = ymin; y <= ymax; y++) {\n            int z = zmin;\n            while (z <= zmax) {\n                while (z <= zmax && !mark[idx3(x, y, z)]) z++;\n                if (z > zmax) break;\n                int z0 = z;\n                while (z <= zmax && mark[idx3(x, y, z)]) z++;\n                out.push_back({2, x, y, z0, z - z0});\n            }\n        }\n    }\n\n    for (int id : comp.cells) mark[id] = 0;\n}\n\nAxisDecomp best_component_axis(const ShapeComp& comp) {\n    static array<uint8_t, MAXN> mark;\n\n    AxisDecomp best;\n    int xmin = D, xmax = -1, ymin = D, ymax = -1, zmin = D, zmax = -1;\n    for (int id : comp.cells) {\n        mark[id] = 1;\n        int x, y, z;\n        decode3(id, x, y, z);\n        xmin = min(xmin, x); xmax = max(xmax, x);\n        ymin = min(ymin, y); ymax = max(ymax, y);\n        zmin = min(zmin, z); zmax = max(zmax, z);\n    }\n\n    auto upd = [&](AxisDecomp&& cur) {\n        if (cur.sumSq > best.sumSq ||\n            (cur.sumSq == best.sumSq && cur.maxLen > best.maxLen) ||\n            (cur.sumSq == best.sumSq && cur.maxLen == best.maxLen && cur.numSeg < best.numSeg)) {\n            best = std::move(cur);\n        }\n    };\n\n    for (int axis = 0; axis < 3; axis++) {\n        AxisDecomp cur;\n        cur.axis = axis;\n        if (axis == 0) {\n            for (int y = ymin; y <= ymax; y++) for (int z = zmin; z <= zmax; z++) {\n                int x = xmin;\n                while (x <= xmax) {\n                    while (x <= xmax && !mark[idx3(x, y, z)]) x++;\n                    if (x > xmax) break;\n                    int x0 = x;\n                    while (x <= xmax && mark[idx3(x, y, z)]) x++;\n                    int len = x - x0;\n                    cur.segs.push_back({0, x0, y, z, len});\n                    cur.sumSq += 1LL * len * len;\n                    cur.maxLen = max(cur.maxLen, len);\n                }\n            }\n        } else if (axis == 1) {\n            for (int x = xmin; x <= xmax; x++) for (int z = zmin; z <= zmax; z++) {\n                int y = ymin;\n                while (y <= ymax) {\n                    while (y <= ymax && !mark[idx3(x, y, z)]) y++;\n                    if (y > ymax) break;\n                    int y0 = y;\n                    while (y <= ymax && mark[idx3(x, y, z)]) y++;\n                    int len = y - y0;\n                    cur.segs.push_back({1, x, y0, z, len});\n                    cur.sumSq += 1LL * len * len;\n                    cur.maxLen = max(cur.maxLen, len);\n                }\n            }\n        } else {\n            for (int x = xmin; x <= xmax; x++) for (int y = ymin; y <= ymax; y++) {\n                int z = zmin;\n                while (z <= zmax) {\n                    while (z <= zmax && !mark[idx3(x, y, z)]) z++;\n                    if (z > zmax) break;\n                    int z0 = z;\n                    while (z <= zmax && mark[idx3(x, y, z)]) z++;\n                    int len = z - z0;\n                    cur.segs.push_back({2, x, y, z0, len});\n                    cur.sumSq += 1LL * len * len;\n                    cur.maxLen = max(cur.maxLen, len);\n                }\n            }\n        }\n        cur.numSeg = (int)cur.segs.size();\n        upd(std::move(cur));\n    }\n\n    for (int id : comp.cells) mark[id] = 0;\n    return best;\n}\n\nlong double match_score_lengths(const vector<LineSeg>& s1, const vector<LineSeg>& s2) {\n    priority_queue<int> pq1, pq2;\n    for (auto &s : s1) pq1.push(s.len);\n    for (auto &s : s2) pq2.push(s.len);\n\n    long double sc = 0.0L;\n    long long exclusive = 0;\n\n    while (!pq1.empty() && !pq2.empty()) {\n        int a = pq1.top(); pq1.pop();\n        int b = pq2.top(); pq2.pop();\n        int m = min(a, b);\n        sc += 1.0L / (long double)m;\n        if (a > m) pq1.push(a - m);\n        if (b > m) pq2.push(b - m);\n    }\n    while (!pq1.empty()) {\n        exclusive += pq1.top();\n        pq1.pop();\n    }\n    while (!pq2.empty()) {\n        exclusive += pq2.top();\n        pq2.pop();\n    }\n    sc += (long double)exclusive;\n    return sc;\n}\n\nPairPlan make_pair_plan(const Candidate& c1, const Candidate& c2) {\n    PairPlan plan;\n\n    unordered_map<string, vector<int>> mp1, mp2;\n    mp1.reserve(c1.comps.size() * 2 + 1);\n    mp2.reserve(c2.comps.size() * 2 + 1);\n\n    for (int i = 0; i < (int)c1.comps.size(); i++) mp1[c1.comps[i].sig].push_back(i);\n    for (int i = 0; i < (int)c2.comps.size(); i++) mp2[c2.comps[i].sig].push_back(i);\n\n    vector<char> used1(c1.comps.size(), 0), used2(c2.comps.size(), 0);\n\n    for (auto &kv : mp1) {\n        auto it = mp2.find(kv.first);\n        if (it == mp2.end()) continue;\n        int cnt = min((int)kv.second.size(), (int)it->second.size());\n        for (int t = 0; t < cnt; t++) {\n            int i = kv.second[t];\n            int j = it->second[t];\n            used1[i] = 1;\n            used2[j] = 1;\n            plan.matchedExtra.push_back({i, j});\n            plan.extraScore += 1.0L / (long double)c1.comps[i].vol;\n        }\n    }\n\n    array<uint8_t, MAXN> res1{}, res2{};\n    res1.fill(0);\n    res2.fill(0);\n\n    for (int i = 0; i < (int)c1.comps.size(); i++) if (!used1[i]) {\n        for (int id : c1.comps[i].cells) res1[id] = 1;\n    }\n    for (int i = 0; i < (int)c2.comps.size(); i++) if (!used2[i]) {\n        for (int id : c2.comps[i].cells) res2[id] = 1;\n    }\n\n    vector<LineSeg> g1[3], g2[3];\n    for (int a = 0; a < 3; a++) {\n        extract_segments_axis(res1, a, g1[a]);\n        extract_segments_axis(res2, a, g2[a]);\n    }\n\n    vector<int> compAxis1(c1.comps.size(), -1), compAxis2(c2.comps.size(), -1);\n    vector<LineSeg> cseg1, cseg2;\n    for (int i = 0; i < (int)c1.comps.size(); i++) if (!used1[i]) {\n        AxisDecomp d = best_component_axis(c1.comps[i]);\n        compAxis1[i] = d.axis;\n        cseg1.insert(cseg1.end(), d.segs.begin(), d.segs.end());\n    }\n    for (int i = 0; i < (int)c2.comps.size(); i++) if (!used2[i]) {\n        AxisDecomp d = best_component_axis(c2.comps[i]);\n        compAxis2[i] = d.axis;\n        cseg2.insert(cseg2.end(), d.segs.begin(), d.segs.end());\n    }\n\n    long double bestRes = 1e100L;\n\n    auto apply_if_better = [&](long double sc, int m1, int a1, const vector<int>* ca1,\n                               int m2, int a2, const vector<int>* ca2) {\n        if (sc < bestRes) {\n            bestRes = sc;\n            plan.mode1 = m1;\n            plan.mode2 = m2;\n            plan.axis1 = a1;\n            plan.axis2 = a2;\n            plan.compAxis1 = (ca1 ? *ca1 : vector<int>());\n            plan.compAxis2 = (ca2 ? *ca2 : vector<int>());\n        }\n    };\n\n    for (int a1 = 0; a1 < 3; a1++) for (int a2 = 0; a2 < 3; a2++) {\n        apply_if_better(match_score_lengths(g1[a1], g2[a2]), 0, a1, nullptr, 0, a2, nullptr);\n    }\n    for (int a2 = 0; a2 < 3; a2++) {\n        apply_if_better(match_score_lengths(cseg1, g2[a2]), 1, 0, &compAxis1, 0, a2, nullptr);\n    }\n    for (int a1 = 0; a1 < 3; a1++) {\n        apply_if_better(match_score_lengths(g1[a1], cseg2), 0, a1, nullptr, 1, 0, &compAxis2);\n    }\n    apply_if_better(match_score_lengths(cseg1, cseg2), 1, 0, &compAxis1, 1, 0, &compAxis2);\n\n    plan.extraScore += bestRes;\n    return plan;\n}\n\nvector<int> select_thresholds() {\n    vector<int> u;\n    for (auto &c : commonComps) u.push_back(c.vol);\n    sort(u.begin(), u.end());\n    u.erase(unique(u.begin(), u.end()), u.end());\n\n    vector<int> th;\n    auto add = [&](int v) {\n        if (find(th.begin(), th.end(), v) == th.end()) th.push_back(v);\n    };\n\n    add(-1);\n\n    if (u.empty()) {\n        sort(th.begin(), th.end());\n        return th;\n    }\n\n    int m = (int)u.size();\n    for (int i = 0; i < min(m, 6); i++) add(u[i] - 1);\n    add(u[m / 4] - 1);\n    add(u[m / 2] - 1);\n    add(u[(3 * m) / 4] - 1);\n    add(u.back() - 1);\n    add(u.back());\n\n    sort(th.begin(), th.end());\n    th.erase(unique(th.begin(), th.end()), th.end());\n    return th;\n}\n\nstring occ_key(const array<uint8_t, MAXN>& occ) {\n    return string(reinterpret_cast<const char*>(occ.data()), Ncells);\n}\n\nState make_state(const CoreInfo& core, const EvalResult& ev) {\n    State s;\n    s.ok = ev.ok;\n    s.score = ev.score;\n    s.core = core;\n    s.c1 = ev.c1;\n    s.c2 = ev.c2;\n    s.plan = ev.plan;\n    return s;\n}\n\nvoid insert_elite(vector<State>& elites, const State& s, int K) {\n    if (!s.ok) return;\n    elites.push_back(s);\n    sort(elites.begin(), elites.end(), [](const State& a, const State& b) {\n        return a.score < b.score;\n    });\n    if ((int)elites.size() > K) elites.resize(K);\n}\n\nEvalResult evaluate_core(const CoreInfo& core, const vector<Param>& dpParams, double timeLimit) {\n    EvalResult res;\n    build_runs(core);\n\n    vector<Candidate> cand[2];\n\n    for (int obj = 0; obj < 2; obj++) {\n        unordered_set<string> seen;\n        seen.reserve(64);\n\n        auto push_candidate = [&](Candidate&& c) {\n            string key = occ_key(c.occ);\n            if (seen.insert(key).second) cand[obj].push_back(std::move(c));\n        };\n\n        for (auto &prm : dpParams) {\n            if (elapsed_sec() > timeLimit && !cand[obj].empty()) break;\n            push_candidate(build_candidate_dp(obj, core, prm));\n        }\n\n        for (int pat = 0; pat < 4; pat++) {\n            if (elapsed_sec() > timeLimit && !cand[obj].empty()) break;\n            bool revA = (pat >> 1) & 1;\n            bool revB = pat & 1;\n            push_candidate(build_candidate_group_shift(obj, core, revA, revB, 0));\n        }\n\n        int shift1 = max(1, D / 3);\n        int shift2 = max(1, (2 * D) / 3);\n        push_candidate(build_candidate_group_shift(obj, core, false, false, shift1));\n        push_candidate(build_candidate_group_shift(obj, core, true, true, shift2));\n\n        if (cand[obj].empty()) {\n            push_candidate(build_candidate_dp(obj, core, dpParams[0]));\n        }\n    }\n\n    for (auto &c1 : cand[0]) {\n        if (elapsed_sec() > timeLimit + 0.05) break;\n        for (auto &c2 : cand[1]) {\n            PairPlan plan = make_pair_plan(c1, c2);\n            long double sc = core.scoreCore + plan.extraScore;\n            if (!res.ok || sc < res.score) {\n                res.ok = true;\n                res.score = sc;\n                res.c1 = c1;\n                res.c2 = c2;\n                res.plan = std::move(plan);\n            }\n        }\n    }\n\n    if (!res.ok) return res;\n\n    vector<pair<Param,int>> guidedCfgs = {\n        {{+1, 12000,  400, 91},  90000},\n        {{-1, 12000,  400, 92},  90000},\n        {{+1,  4000, 1400, 93},  30000},\n        {{-1,  4000, 1400, 94},  30000},\n    };\n\n    for (int round = 0; round < 2; round++) {\n        if (elapsed_sec() > timeLimit + 0.08) break;\n        bool improved = false;\n\n        for (int side = 0; side < 2; side++) {\n            if (elapsed_sec() > timeLimit + 0.08) break;\n\n            unordered_set<string> seen;\n            seen.reserve(guidedCfgs.size() * 2 + 1);\n\n            const array<uint8_t, MAXN>& pref = (side == 0 ? res.c2.occ : res.c1.occ);\n            for (auto &cfg : guidedCfgs) {\n                Candidate gc = build_candidate_dp(side, core, cfg.first, &pref, cfg.second);\n                string key = occ_key(gc.occ);\n                if (!seen.insert(key).second) continue;\n\n                long double sc;\n                PairPlan plan;\n                if (side == 0) {\n                    plan = make_pair_plan(gc, res.c2);\n                    sc = core.scoreCore + plan.extraScore;\n                    if (sc + 1e-15L < res.score) {\n                        improved = true;\n                        res.score = sc;\n                        res.c1 = std::move(gc);\n                        res.plan = std::move(plan);\n                    }\n                } else {\n                    plan = make_pair_plan(res.c1, gc);\n                    sc = core.scoreCore + plan.extraScore;\n                    if (sc + 1e-15L < res.score) {\n                        improved = true;\n                        res.score = sc;\n                        res.c2 = std::move(gc);\n                        res.plan = std::move(plan);\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return res;\n}\n\nCandidate build_random_candidate(int obj, const CoreInfo& core, const Candidate& other, XorShift64& rng) {\n    int typ = rng.nextInt(100);\n    if (typ < 75) {\n        static const int AV[] = {120000, 80000, 40000, 20000, 10000, 4000, 1500, 600};\n        static const int BV[] = {0, 50, 150, 400, 900, 1800, 3500};\n        static const int OV[] = {0, 3000, 8000, 20000, 60000, 150000};\n\n        Param prm;\n        prm.dir = (rng.nextInt(2) ? +1 : -1);\n        prm.alpha = AV[rng.nextInt((int)(sizeof(AV) / sizeof(AV[0])))];\n        prm.beta  = BV[rng.nextInt((int)(sizeof(BV) / sizeof(BV[0])))];\n        prm.seed  = (int)(rng.next() & 0x7fffffff);\n\n        bool usePref = rng.nextInt(100) < 70;\n        int overlapBonus = OV[rng.nextInt((int)(sizeof(OV) / sizeof(OV[0])))];\n\n        if (usePref) return build_candidate_dp(obj, core, prm, &other.occ, overlapBonus);\n        return build_candidate_dp(obj, core, prm, nullptr, 0);\n    } else {\n        bool revA = rng.nextInt(2);\n        bool revB = rng.nextInt(2);\n        int shift = rng.nextInt(max(1, D));\n        return build_candidate_group_shift(obj, core, revA, revB, shift);\n    }\n}\n\nvoid stochastic_refine_state(State& st, XorShift64& rng, double deadline) {\n    if (!st.ok) return;\n    build_runs(st.core);\n\n    unordered_set<string> seen1, seen2;\n    seen1.reserve(512);\n    seen2.reserve(512);\n    seen1.insert(occ_key(st.c1.occ));\n    seen2.insert(occ_key(st.c2.occ));\n\n    int iter = 0;\n    while (elapsed_sec() < deadline) {\n        ++iter;\n\n        if (iter % 6 == 0) {\n            int first = rng.nextInt(2);\n            if (first == 0) {\n                Candidate a = build_random_candidate(0, st.core, st.c2, rng);\n                Candidate b = build_random_candidate(1, st.core, a, rng);\n                PairPlan plan = make_pair_plan(a, b);\n                long double sc = st.core.scoreCore + plan.extraScore;\n                if (sc + 1e-15L < st.score) {\n                    st.score = sc;\n                    st.c1 = std::move(a);\n                    st.c2 = std::move(b);\n                    st.plan = std::move(plan);\n                    seen1.insert(occ_key(st.c1.occ));\n                    seen2.insert(occ_key(st.c2.occ));\n                }\n            } else {\n                Candidate b = build_random_candidate(1, st.core, st.c1, rng);\n                Candidate a = build_random_candidate(0, st.core, b, rng);\n                PairPlan plan = make_pair_plan(a, b);\n                long double sc = st.core.scoreCore + plan.extraScore;\n                if (sc + 1e-15L < st.score) {\n                    st.score = sc;\n                    st.c1 = std::move(a);\n                    st.c2 = std::move(b);\n                    st.plan = std::move(plan);\n                    seen1.insert(occ_key(st.c1.occ));\n                    seen2.insert(occ_key(st.c2.occ));\n                }\n            }\n            continue;\n        }\n\n        int side = (iter & 1);\n\n        Candidate cand = build_random_candidate(side, st.core, (side == 0 ? st.c2 : st.c1), rng);\n        string key = occ_key(cand.occ);\n        auto& seen = (side == 0 ? seen1 : seen2);\n        if (!seen.insert(key).second) continue;\n\n        PairPlan plan;\n        long double sc;\n        if (side == 0) {\n            plan = make_pair_plan(cand, st.c2);\n            sc = st.core.scoreCore + plan.extraScore;\n            if (sc + 1e-15L < st.score) {\n                st.score = sc;\n                st.c1 = std::move(cand);\n                st.plan = std::move(plan);\n            }\n        } else {\n            plan = make_pair_plan(st.c1, cand);\n            sc = st.core.scoreCore + plan.extraScore;\n            if (sc + 1e-15L < st.score) {\n                st.score = sc;\n                st.c2 = std::move(cand);\n                st.plan = std::move(plan);\n            }\n        }\n    }\n}\n\nvoid fill_line_seg(array<int, MAXN>& out, LineSeg s, int len, int label) {\n    for (int t = 0; t < len; t++) {\n        int x = s.x, y = s.y, z = s.z;\n        if (s.axis == 0) x += t;\n        else if (s.axis == 1) y += t;\n        else z += t;\n        out[idx3(x, y, z)] = label;\n    }\n}\nvoid advance_seg(LineSeg& s, int used) {\n    if (s.axis == 0) s.x += used;\n    else if (s.axis == 1) s.y += used;\n    else s.z += used;\n    s.len -= used;\n}\n\nvoid assign_final_labels(\n    const CoreInfo& core,\n    const Candidate& cand1,\n    const Candidate& cand2,\n    const PairPlan& plan,\n    array<int, MAXN>& out1,\n    array<int, MAXN>& out2,\n    int& nblocks\n) {\n    out1.fill(0);\n    out2.fill(0);\n    nblocks = 0;\n\n    for (int cid = 0; cid < (int)commonComps.size(); cid++) {\n        if (!core.keep[cid]) continue;\n        ++nblocks;\n        for (int id : commonComps[cid].cells) {\n            out1[id] = nblocks;\n            out2[id] = nblocks;\n        }\n    }\n\n    vector<char> used1(cand1.comps.size(), 0), used2(cand2.comps.size(), 0);\n    for (auto [i, j] : plan.matchedExtra) {\n        used1[i] = 1;\n        used2[j] = 1;\n        ++nblocks;\n        for (int id : cand1.comps[i].cells) out1[id] = nblocks;\n        for (int id : cand2.comps[j].cells) out2[id] = nblocks;\n    }\n\n    vector<LineSeg> s1, s2;\n\n    if (plan.mode1 == 0) {\n        array<uint8_t, MAXN> res1{};\n        res1.fill(0);\n        for (int i = 0; i < (int)cand1.comps.size(); i++) if (!used1[i]) {\n            for (int id : cand1.comps[i].cells) res1[id] = 1;\n        }\n        extract_segments_axis(res1, plan.axis1, s1);\n    } else {\n        for (int i = 0; i < (int)cand1.comps.size(); i++) if (!used1[i]) {\n            append_component_axis_segments(cand1.comps[i], plan.compAxis1[i], s1);\n        }\n    }\n\n    if (plan.mode2 == 0) {\n        array<uint8_t, MAXN> res2{};\n        res2.fill(0);\n        for (int i = 0; i < (int)cand2.comps.size(); i++) if (!used2[i]) {\n            for (int id : cand2.comps[i].cells) res2[id] = 1;\n        }\n        extract_segments_axis(res2, plan.axis2, s2);\n    } else {\n        for (int i = 0; i < (int)cand2.comps.size(); i++) if (!used2[i]) {\n            append_component_axis_segments(cand2.comps[i], plan.compAxis2[i], s2);\n        }\n    }\n\n    priority_queue<LineSeg, vector<LineSeg>, LineSegCmp> pq1, pq2;\n    for (auto &s : s1) pq1.push(s);\n    for (auto &s : s2) pq2.push(s);\n\n    while (!pq1.empty() && !pq2.empty()) {\n        LineSeg a = pq1.top(); pq1.pop();\n        LineSeg b = pq2.top(); pq2.pop();\n        int m = min(a.len, b.len);\n        ++nblocks;\n        fill_line_seg(out1, a, m, nblocks);\n        fill_line_seg(out2, b, m, nblocks);\n\n        if (a.len > m) {\n            advance_seg(a, m);\n            pq1.push(a);\n        }\n        if (b.len > m) {\n            advance_seg(b, m);\n            pq2.push(b);\n        }\n    }\n    while (!pq1.empty()) {\n        LineSeg a = pq1.top(); pq1.pop();\n        ++nblocks;\n        fill_line_seg(out1, a, a.len, nblocks);\n    }\n    while (!pq2.empty()) {\n        LineSeg b = pq2.top(); pq2.pop();\n        ++nblocks;\n        fill_line_seg(out2, b, b.len, nblocks);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> D;\n    Ncells = D * D * D;\n    init_rotations();\n\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) cin >> fstr[i][z];\n        for (int z = 0; z < D; z++) cin >> rstr[i][z];\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        for (int z = 0; z < D; z++) {\n            actXMask[obj][z] = 0;\n            actYMask[obj][z] = 0;\n            actXList[obj][z].clear();\n            actYList[obj][z].clear();\n\n            for (int x = 0; x < D; x++) {\n                if (fstr[obj][z][x] == '1') {\n                    actXMask[obj][z] |= (uint16_t(1) << x);\n                    actXList[obj][z].push_back(x);\n                }\n            }\n            for (int y = 0; y < D; y++) {\n                if (rstr[obj][z][y] == '1') {\n                    actYMask[obj][z] |= (uint16_t(1) << y);\n                    actYList[obj][z].push_back(y);\n                }\n            }\n\n            for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) {\n                activeCell[obj][x][y][z] =\n                    (fstr[obj][z][x] == '1' && rstr[obj][z][y] == '1') ? 1 : 0;\n            }\n        }\n    }\n\n    build_full_common_components();\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)D + 0x9e3779b97f4a7c15ull;\n    seed *= 1099511628211ull;\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) for (char c : fstr[i][z]) {\n            seed ^= (uint64_t)c;\n            seed *= 1099511628211ull;\n        }\n        for (int z = 0; z < D; z++) for (char c : rstr[i][z]) {\n            seed ^= (uint64_t)c;\n            seed *= 1099511628211ull;\n        }\n    }\n    XorShift64 rng(seed);\n\n    vector<Param> dpParams = {\n        {+1, 100000,    0, 1},\n        {-1, 100000,    0, 1},\n        {+1,  25000,  200, 2},\n        {-1,  25000,  200, 2},\n        {+1,   6000, 1200, 3},\n        {-1,   6000, 1200, 3},\n    };\n\n    vector<int> thresholds = select_thresholds();\n\n    State bestState;\n    vector<State> elites;\n    const int ELITE_K = 3;\n\n    vector<CoreInfo> cores;\n    for (int th : thresholds) cores.push_back(build_core_by_threshold(th));\n\n    sort(cores.begin(), cores.end(), [&](const CoreInfo& a, const CoreInfo& b) {\n        long double la = a.scoreCore + (long double)abs(a.remVol[0] - a.remVol[1]);\n        long double lb = b.scoreCore + (long double)abs(b.remVol[0] - b.remVol[1]);\n        return la < lb;\n    });\n\n    for (const CoreInfo& core : cores) {\n        if (elapsed_sec() > 4.10) break;\n        long double lb = core.scoreCore + (long double)abs(core.remVol[0] - core.remVol[1]);\n        if (bestState.ok && lb >= bestState.score - 1e-15L) continue;\n\n        EvalResult ev = evaluate_core(core, dpParams, 4.45);\n        if (ev.ok) {\n            State st = make_state(core, ev);\n            insert_elite(elites, st, ELITE_K);\n            if (!bestState.ok || st.score < bestState.score) bestState = st;\n        }\n    }\n\n    if (!bestState.ok) {\n        CoreInfo core = build_core_by_threshold((int)1e9);\n        EvalResult ev = evaluate_core(core, dpParams, 4.45);\n        if (ev.ok) {\n            bestState = make_state(core, ev);\n            insert_elite(elites, bestState, ELITE_K);\n        } else {\n            bestState.ok = true;\n            bestState.core = core;\n            build_runs(core);\n            bestState.c1 = build_candidate_dp(0, core, dpParams[0]);\n            bestState.c2 = build_candidate_dp(1, core, dpParams[0]);\n            bestState.plan = make_pair_plan(bestState.c1, bestState.c2);\n            bestState.score = core.scoreCore + bestState.plan.extraScore;\n            insert_elite(elites, bestState, ELITE_K);\n        }\n    }\n\n    if (!commonComps.empty() && elapsed_sec() < 4.90) {\n        vector<char> curKeep = bestState.core.keep;\n\n        for (int phase = 0; phase < 2 && elapsed_sec() < 5.10; phase++) {\n            vector<int> rem, add;\n            for (int i = 0; i < (int)commonComps.size(); i++) {\n                if (curKeep[i]) rem.push_back(i);\n                else add.push_back(i);\n            }\n            sort(rem.begin(), rem.end(), [&](int a, int b) {\n                if (commonComps[a].vol != commonComps[b].vol) return commonComps[a].vol < commonComps[b].vol;\n                return a < b;\n            });\n            sort(add.begin(), add.end(), [&](int a, int b) {\n                if (commonComps[a].vol != commonComps[b].vol) return commonComps[a].vol > commonComps[b].vol;\n                return a < b;\n            });\n\n            vector<int> order;\n            int LIM1 = min<int>(16, rem.size());\n            int LIM2 = min<int>(16, add.size());\n            for (int i = 0; i < LIM1; i++) order.push_back(rem[i]);\n            for (int i = 0; i < LIM2; i++) order.push_back(add[i]);\n            if (phase == 1) reverse(order.begin(), order.end());\n\n            bool improved = false;\n\n            for (int cid : order) {\n                if (elapsed_sec() > 5.15) break;\n\n                vector<char> nk = curKeep;\n                nk[cid] ^= 1;\n                CoreInfo nc = build_core_from_keep(nk);\n                long double lb = nc.scoreCore + (long double)abs(nc.remVol[0] - nc.remVol[1]);\n                if (lb >= bestState.score - 1e-15L) continue;\n\n                EvalResult ev = evaluate_core(nc, dpParams, 5.00);\n                if (ev.ok) {\n                    State st = make_state(nc, ev);\n                    insert_elite(elites, st, ELITE_K);\n                    if (st.score + 1e-15L < bestState.score) {\n                        improved = true;\n                        curKeep = std::move(nk);\n                        bestState = st;\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    if (elites.empty()) elites.push_back(bestState);\n    sort(elites.begin(), elites.end(), [](const State& a, const State& b) { return a.score < b.score; });\n    if (elites[0].score < bestState.score) bestState = elites[0];\n\n    double finalDeadline = 5.76;\n    int ptr = 0;\n    while (elapsed_sec() < finalDeadline) {\n        if (elites.empty()) break;\n        int id = ptr % (int)elites.size();\n        ptr++;\n        double slice = min(finalDeadline, elapsed_sec() + 0.16);\n        stochastic_refine_state(elites[id], rng, slice);\n        sort(elites.begin(), elites.end(), [](const State& a, const State& b) { return a.score < b.score; });\n        if (elites[0].score < bestState.score) bestState = elites[0];\n    }\n\n    array<int, MAXN> out1, out2;\n    int nblocks = 0;\n    assign_final_labels(bestState.core, bestState.c1, bestState.c2, bestState.plan, out1, out2, nblocks);\n\n    cout << nblocks << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out2[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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 leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n};\n\nstruct Candidate {\n    vector<int> P;\n    vector<char> B;\n    int covered = -1;\n    long long cost = (1LL << 62);\n};\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> B;\n};\n\nclass Solver {\npublic:\n    int N, M, K;\n    vector<int> xs, ys;\n    vector<Edge> edges;\n    vector<int> as, bs;\n\n    vector<vector<int>> req; // req[i][k] = minimum power to cover resident k, or 5001\n    vector<vector<pair<int,int>>> lists; // (required power, resident id), sorted\n    vector<vector<int>> incident;\n    vector<vector<int>> eidMat;\n\n    vector<vector<long long>> sp;\n    vector<vector<int>> nxt;\n\n    chrono::steady_clock::time_point t0;\n    static constexpr long long INF64 = (1LL << 60);\n    static constexpr double HARD_LIMIT = 1.92;\n\n    void input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> K;\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n        edges.resize(M);\n        incident.assign(N, {});\n        eidMat.assign(N, vector<int>(N, -1));\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, v, w};\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            eidMat[u][v] = eidMat[v][u] = i;\n        }\n\n        as.resize(K);\n        bs.resize(K);\n        for (int k = 0; k < K; k++) cin >> as[k] >> bs[k];\n    }\n\n    double elapsed() const {\n        auto t = chrono::steady_clock::now();\n        return chrono::duration<double>(t - t0).count();\n    }\n\n    static int ceil_sqrt_ll(long long x) {\n        long long r = sqrt((long double)x);\n        while (r * r < x) ++r;\n        while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n        return (int)r;\n    }\n\n    void precompute() {\n        req.assign(N, vector<int>(K, 5001));\n        lists.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            lists[i].reserve(K / 2);\n            for (int k = 0; k < K; k++) {\n                long long dx = (long long)xs[i] - as[k];\n                long long dy = (long long)ys[i] - bs[k];\n                long long d2 = dx * dx + dy * dy;\n                int r = ceil_sqrt_ll(d2);\n                if (r <= 5000) {\n                    req[i][k] = r;\n                    lists[i].push_back({r, k});\n                }\n            }\n            sort(lists[i].begin(), lists[i].end());\n        }\n\n        sp.assign(N, vector<long long>(N, INF64));\n        nxt.assign(N, vector<int>(N, -1));\n        for (int i = 0; i < N; i++) {\n            sp[i][i] = 0;\n            nxt[i][i] = i;\n        }\n        for (int e = 0; e < M; e++) {\n            auto [u, v, w] = edges[e];\n            if (w < sp[u][v]) {\n                sp[u][v] = sp[v][u] = w;\n                nxt[u][v] = v;\n                nxt[v][u] = u;\n            }\n        }\n        for (int k = 0; k < N; k++) {\n            for (int i = 0; i < N; i++) if (sp[i][k] < INF64) {\n                for (int j = 0; j < N; j++) if (sp[k][j] < INF64) {\n                    long long nd = sp[i][k] + sp[k][j];\n                    if (nd < sp[i][j]) {\n                        sp[i][j] = nd;\n                        nxt[i][j] = nxt[i][k];\n                    }\n                }\n            }\n        }\n\n        t0 = chrono::steady_clock::now();\n    }\n\n    vector<long double> make_gain_table(long double gamma) const {\n        vector<long double> gain(K + 1, 0);\n        if (fabsl(gamma - 1.0L) < 1e-18L) {\n            for (int i = 1; i <= K; i++) gain[i] = (long double)i;\n        } else {\n            for (int i = 1; i <= K; i++) gain[i] = powl((long double)i, gamma);\n        }\n        return gain;\n    }\n\n    vector<int> reconstruct_path_vertices(int s, int t) const {\n        vector<int> path;\n        if (nxt[s][t] == -1) return path;\n        int cur = s;\n        path.push_back(cur);\n        while (cur != t) {\n            cur = nxt[cur][t];\n            path.push_back(cur);\n        }\n        return path;\n    }\n\n    void recompute_nearest_tree(\n        const vector<char>& inTree,\n        vector<long long>& distToTree,\n        vector<int>& nearTree\n    ) const {\n        distToTree.assign(N, INF64);\n        nearTree.assign(N, -1);\n        for (int i = 0; i < N; i++) {\n            if (inTree[i]) {\n                distToTree[i] = 0;\n                nearTree[i] = i;\n                continue;\n            }\n            long long best = INF64;\n            int bestv = -1;\n            for (int v = 0; v < N; v++) if (inTree[v]) {\n                if (sp[v][i] < best) {\n                    best = sp[v][i];\n                    bestv = v;\n                }\n            }\n            distToTree[i] = best;\n            nearTree[i] = bestv;\n        }\n    }\n\n    long long edge_cost(const vector<char>& B) const {\n        long long c = 0;\n        for (int i = 0; i < M; i++) if (B[i]) c += edges[i].w;\n        return c;\n    }\n\n    long long power_cost(const vector<int>& P) const {\n        long long c = 0;\n        for (int i = 0; i < N; i++) c += 1LL * P[i] * P[i];\n        return c;\n    }\n\n    vector<char> terminals_from_P(const vector<int>& P) const {\n        vector<char> term(N, 0);\n        term[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) term[i] = 1;\n        return term;\n    }\n\n    vector<char> tree_vertices(const vector<char>& B) const {\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 (int eid : incident[v]) if (B[eid]) {\n                int to = edges[eid].u ^ edges[eid].v ^ v;\n                if (!vis[to]) {\n                    vis[to] = 1;\n                    q.push(to);\n                }\n            }\n        }\n        return vis;\n    }\n\n    vector<int> degrees_from_B(const vector<char>& B) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n        return deg;\n    }\n\n    void prune_nonterminal_leaves(vector<char>& B, const vector<char>& terminal) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n\n        queue<int> q;\n        for (int v = 0; v < N; v++) {\n            if (v != 0 && !terminal[v] && deg[v] == 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            if (v == 0 || terminal[v] || deg[v] != 1) continue;\n\n            int remE = -1, to = -1;\n            for (int eid : incident[v]) if (B[eid]) {\n                remE = eid;\n                to = edges[eid].u ^ edges[eid].v ^ v;\n                break;\n            }\n            if (remE == -1) continue;\n\n            B[remE] = 0;\n            deg[v]--;\n            deg[to]--;\n            if (to != 0 && !terminal[to] && deg[to] == 1) q.push(to);\n        }\n    }\n\n    vector<char> build_tree_metric(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n\n        vector<int> ids;\n        ids.push_back(0);\n        for (int i = 1; i < N; i++) if (terminal[i]) ids.push_back(i);\n\n        int T = (int)ids.size();\n        if (T <= 1) return used;\n\n        // Prim on metric closure.\n        vector<long long> minD(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> vis(T, 0);\n        minD[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            for (int i = 0; i < T; i++) {\n                if (!vis[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            vis[v] = 1;\n            for (int u = 0; u < T; u++) if (!vis[u]) {\n                if (sp[ids[v]][ids[u]] < minD[u]) {\n                    minD[u] = sp[ids[v]][ids[u]];\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<char> cand(M, 0);\n        vector<int> candEdges;\n        for (int i = 1; i < T; i++) {\n            auto path = reconstruct_path_vertices(ids[i], ids[par[i]]);\n            for (int j = 0; j + 1 < (int)path.size(); j++) {\n                int a = path[j], b = path[j + 1];\n                int eid = eidMat[a][b];\n                if (eid >= 0 && !cand[eid]) {\n                    cand[eid] = 1;\n                    candEdges.push_back(eid);\n                }\n            }\n        }\n\n        sort(candEdges.begin(), candEdges.end(), [&](int e1, int e2) {\n            if (edges[e1].w != edges[e2].w) return edges[e1].w < edges[e2].w;\n            return e1 < e2;\n        });\n\n        DSU dsu(N);\n        for (int eid : candEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            if (dsu.merge(u, v)) used[eid] = 1;\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_sph(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n        vector<char> inTree(N, 0);\n        vector<char> left = terminal;\n        inTree[0] = 1;\n        left[0] = 0;\n\n        int rem = 0;\n        for (int i = 0; i < N; i++) if (left[i]) rem++;\n\n        if (rem == 0) return used;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        while (rem > 0) {\n            int best = -1;\n            long long bestD = INF64;\n            for (int i = 0; i < N; i++) if (left[i]) {\n                if (distToTree[i] < bestD) {\n                    bestD = distToTree[i];\n                    best = i;\n                }\n            }\n            if (best == -1) break;\n\n            int from = nearTree[best];\n            auto path = reconstruct_path_vertices(from, best);\n\n            int lastTreeIdx = 0;\n            for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n            for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                int u = path[i], v = path[i + 1];\n                int eid = eidMat[u][v];\n                if (eid >= 0) used[eid] = 1;\n                inTree[u] = 1;\n                inTree[v] = 1;\n            }\n            left[best] = 0;\n            rem--;\n\n            recompute_nearest_tree(inTree, distToTree, nearTree);\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_best(const vector<char>& terminal) const {\n        auto b1 = build_tree_metric(terminal);\n        auto b2 = build_tree_sph(terminal);\n        if (edge_cost(b2) < edge_cost(b1)) return b2;\n        return b1;\n    }\n\n    Candidate make_candidate(const vector<int>& Pin, const vector<char>& Bin) const {\n        vector<int> P = Pin;\n        vector<char> B = Bin;\n\n        // Remove disconnected parts.\n        vector<char> reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n        for (int e = 0; e < M; e++) if (B[e]) {\n            int u = edges[e].u, v = edges[e].v;\n            if (!(reach[u] && reach[v])) B[e] = 0;\n        }\n\n        vector<char> terminal(N, 0);\n        terminal[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) terminal[i] = 1;\n        prune_nonterminal_leaves(B, terminal);\n\n        reach = tree_vertices(B);\n        for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (reach[i] && P[i] > 0) active.push_back(i);\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n\n        long long cost = power_cost(P) + edge_cost(B);\n        return {P, B, cov, cost};\n    }\n\n    static bool better(const Candidate& a, const Candidate& b, int K) {\n        if (a.covered != b.covered) return a.covered > b.covered;\n        if (a.covered == K) return a.cost < b.cost;\n        return a.cost < b.cost;\n    }\n\n    int count_covered_by_P(const vector<int>& P) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        if (active.empty()) return 0;\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n        return cov;\n    }\n\n    bool covers_need(const vector<int>& P, const vector<char>& need) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (need[k]) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n        return true;\n    }\n\n    void reduce_powers(vector<int>& P, const vector<char>& allowed) const {\n        while (true) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) {\n                if (allowed[i] && P[i] > 0) active.push_back(i);\n            }\n            sort(active.begin(), active.end(), [&](int a, int b) {\n                if (P[a] != P[b]) return P[a] > P[b];\n                return a < b;\n            });\n\n            bool changed = false;\n            for (int i : active) {\n                int newP = 0;\n                for (const auto& [d, rid] : lists[i]) {\n                    if (d > P[i]) break;\n                    bool other = false;\n                    for (int j : active) {\n                        if (j == i || P[j] == 0) continue;\n                        if (req[j][rid] <= P[j]) {\n                            other = true;\n                            break;\n                        }\n                    }\n                    if (!other) newP = d;\n                }\n                if (newP < P[i]) {\n                    P[i] = newP;\n                    changed = true;\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    vector<int> greedy_cover_subset(\n        const vector<char>& allowed,\n        const vector<int>& Pinit,\n        const vector<char>& needMask,\n        long double gamma,\n        int banned = -1\n    ) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P = Pinit;\n        vector<char> uncoveredNeed = needMask;\n\n        int rem = 0;\n        for (int k = 0; k < K; k++) if (needMask[k]) rem++;\n\n        if (rem == 0) return P;\n\n        // Remove already-covered needed residents.\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (uncoveredNeed[k]) {\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    uncoveredNeed[k] = 0;\n                    rem--;\n                    break;\n                }\n            }\n        }\n        if (rem == 0) return P;\n\n        vector<int> curPos(N, 0);\n        for (int i = 0; i < N; i++) {\n            auto it = upper_bound(lists[i].begin(), lists[i].end(),\n                                  make_pair(P[i], INT_MAX));\n            curPos[i] = (int)(it - lists[i].begin());\n        }\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                if (!allowed[i] || i == banned) continue;\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (uncoveredNeed[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq);\n                    long double metric = num / gain[newcov];\n\n                    bool take = false;\n                    if (metric < bestMetric - 1e-18L) take = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) take = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) take = true;\n                    }\n\n                    if (take) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (uncoveredNeed[rid]) {\n                    uncoveredNeed[rid] = 0;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return P;\n    }\n\n    vector<int> greedy_on_allowed_gamma(const vector<char>& allowed, long double gamma, int banned = -1) const {\n        vector<int> P0(N, 0);\n        vector<char> need(K, 1);\n        return greedy_cover_subset(allowed, P0, need, gamma, banned);\n    }\n\n    InitialState greedy_initial(long double alpha, long double gamma) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P(N, 0);\n        vector<int> curPos(N, 0);\n        vector<char> covered(K, 0);\n        vector<char> usedEdge(M, 0);\n        vector<char> inTree(N, 0);\n        inTree[0] = 1;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        int rem = K;\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                long double conn = inTree[i] ? 0.0L : alpha * (long double)distToTree[i];\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (!covered[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq) + conn;\n                    long double metric = num / gain[newcov];\n\n                    bool better = false;\n                    if (metric < bestMetric - 1e-18L) better = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) better = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) better = true;\n                    }\n                    if (better) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            if (!inTree[bestStation]) {\n                int from = nearTree[bestStation];\n                auto path = reconstruct_path_vertices(from, bestStation);\n\n                int lastTreeIdx = 0;\n                for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n                for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                    int u = path[i], v = path[i + 1];\n                    int eid = eidMat[u][v];\n                    if (eid >= 0) usedEdge[eid] = 1;\n                    inTree[u] = 1;\n                    inTree[v] = 1;\n                }\n\n                recompute_nearest_tree(inTree, distToTree, nearTree);\n            }\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (!covered[rid]) {\n                    covered[rid] = 1;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return {P, usedEdge};\n    }\n\n    Candidate basic_improve(Candidate cur, int rounds) const {\n        for (int it = 0; it < rounds; it++) {\n            if (elapsed() > HARD_LIMIT) break;\n\n            Candidate bestRound = cur;\n\n            auto B0 = build_tree_best(terminals_from_P(cur.P));\n            Candidate c0 = make_candidate(cur.P, B0);\n            if (better(c0, bestRound, K)) bestRound = c0;\n\n            vector<char> allowed = tree_vertices(bestRound.B);\n\n            static const long double gammas[] = {1.0L, 1.10L};\n            for (long double g : gammas) {\n                if (elapsed() > HARD_LIMIT) break;\n                vector<int> P = greedy_on_allowed_gamma(allowed, g);\n                if (count_covered_by_P(P) < K) continue;\n                reduce_powers(P, allowed);\n                auto B = build_tree_best(terminals_from_P(P));\n                Candidate c = make_candidate(P, B);\n                if (better(c, bestRound, K)) bestRound = c;\n            }\n\n            if (better(bestRound, cur, K)) cur = bestRound;\n            else break;\n        }\n        return cur;\n    }\n\n    Candidate try_remove_station(const Candidate& cur, const vector<char>& allowed, int s) const {\n        Candidate best = cur;\n        if (cur.P[s] == 0) return best;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n\n        vector<char> need(K, 0);\n        int needCnt = 0;\n        for (int k = 0; k < K; k++) {\n            if (req[s][k] > cur.P[s]) continue;\n            bool other = false;\n            for (int i : active) {\n                if (i == s) continue;\n                if (req[i][k] <= cur.P[i]) {\n                    other = true;\n                    break;\n                }\n            }\n            if (!other) {\n                need[k] = 1;\n                needCnt++;\n            }\n        }\n\n        vector<int> baseP = cur.P;\n        baseP[s] = 0;\n\n        auto relax_from_P = [&](vector<int> P) {\n            if (elapsed() > HARD_LIMIT) return;\n            if (count_covered_by_P(P) < K) return;\n            reduce_powers(P, allowed);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate c = make_candidate(P, B);\n            if (better(c, best, K)) best = c;\n        };\n\n        if (needCnt == 0) {\n            relax_from_P(baseP);\n        } else {\n            vector<int> P1 = greedy_cover_subset(allowed, baseP, need, 1.0L, s);\n            if (covers_need(P1, need)) relax_from_P(P1);\n\n            if (elapsed() <= HARD_LIMIT) {\n                vector<int> P2 = greedy_cover_subset(allowed, baseP, need, 1.10L, s);\n                if (covers_need(P2, need)) relax_from_P(P2);\n            }\n        }\n\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P3 = greedy_on_allowed_gamma(allowed, 1.0L, s);\n            relax_from_P(P3);\n        }\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P4 = greedy_on_allowed_gamma(allowed, 1.10L, s);\n            relax_from_P(P4);\n        }\n\n        return best;\n    }\n\n    Candidate local_remove(Candidate cur) const {\n        while (elapsed() < HARD_LIMIT) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n            if (active.empty()) break;\n\n            vector<char> allowed = tree_vertices(cur.B);\n            vector<int> deg = degrees_from_B(cur.B);\n\n            vector<int> byPower = active;\n            sort(byPower.begin(), byPower.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> leafs;\n            for (int v : active) if (deg[v] == 1) leafs.push_back(v);\n            sort(leafs.begin(), leafs.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> trials;\n            auto push_unique = [&](int v) {\n                for (int x : trials) if (x == v) return;\n                trials.push_back(v);\n            };\n\n            for (int i = 0; i < (int)leafs.size() && i < 6; i++) push_unique(leafs[i]);\n            for (int i = 0; i < (int)byPower.size() && i < 8; i++) push_unique(byPower[i]);\n\n            bool improved = false;\n            for (int s : trials) {\n                if (elapsed() > HARD_LIMIT) break;\n                Candidate cand = try_remove_station(cur, allowed, s);\n                if (better(cand, cur, K)) {\n                    cur = basic_improve(cand, 1);\n                    improved = true;\n                    break;\n                }\n            }\n            if (!improved) break;\n        }\n        return cur;\n    }\n\n    Candidate solve() {\n        Candidate best;\n\n        auto consider = [&](Candidate c, int rounds = 3) {\n            if (elapsed() > HARD_LIMIT) return;\n            c = basic_improve(c, rounds);\n            if (better(c, best, K)) best = c;\n        };\n\n        vector<pair<long double,long double>> connectedParams = {\n            {0.00L, 1.00L},\n            {0.20L, 1.00L},\n            {0.55L, 1.00L},\n            {1.00L, 1.00L},\n            {0.35L, 1.12L},\n        };\n\n        for (auto [alpha, gamma] : connectedParams) {\n            if (elapsed() > 1.05) break;\n            InitialState init = greedy_initial(alpha, gamma);\n            Candidate cand = make_candidate(init.P, init.B);\n            consider(cand, 3);\n        }\n\n        vector<char> allAllowed(N, 1);\n        vector<long double> globalGammas = {0.92L, 1.00L, 1.10L, 1.18L};\n\n        for (long double g : globalGammas) {\n            if (elapsed() > 1.45) break;\n            vector<int> P = greedy_on_allowed_gamma(allAllowed, g);\n            if (count_covered_by_P(P) < K) continue;\n            reduce_powers(P, allAllowed);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate cand = make_candidate(P, B);\n            consider(cand, 3);\n        }\n\n        // Fallback if somehow empty.\n        if (best.covered < 0) {\n            vector<int> P(N, 0);\n            vector<char> B(M, 0);\n            best = make_candidate(P, B);\n        }\n\n        if (elapsed() < 1.72) best = basic_improve(best, 2);\n        if (elapsed() < 1.86) best = local_remove(best);\n        if (elapsed() < HARD_LIMIT) best = basic_improve(best, 2);\n\n        return best;\n    }\n\n    void output(const Candidate& ans) const {\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans.P[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << int(ans.B[i]);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.input();\n    solver.precompute();\n    Candidate ans = solver.solve();\n    solver.output(ans);\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;\nusing ll = long long;\nusing Board = array<array<int, N>, N>;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    int E = 0;\n\n    long long score_like() const {\n        if ((int)ops.size() > 10000) return -(1LL << 60);\n        if (E == 0) return 100000LL - 5LL * (int)ops.size();\n        return 50000LL - 50LL * E;\n    }\n};\n\nint desired_row[M];\nint noise_tbl[16][N][N];\nchrono::steady_clock::time_point g_start;\n\ndouble elapsed_ms() {\n    auto now = chrono::steady_clock::now();\n    return chrono::duration<double, milli>(now - g_start).count();\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\nvoid prepare_globals() {\n    for (int r = 0; r < N; ++r) {\n        int L = r * (r + 1) / 2;\n        int R = (r + 1) * (r + 2) / 2 - 1;\n        for (int v = L; v <= R && v < M; ++v) desired_row[v] = r;\n    }\n    for (int s = 0; s < 16; ++s) {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                uint64_t h = splitmix64(123456789ULL + 1000003ULL * s + 1009ULL * x + y);\n                noise_tbl[s][x][y] = (int)(h % 19) - 9;\n            }\n        }\n    }\n}\n\ninline int vid(int x, int y) {\n    return x * (x + 1) / 2 + y;\n}\n\nint count_violations(const Board& a) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++E;\n            if (a[x][y] > a[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nBoard reflect_board(const Board& a) {\n    Board b{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            b[x][y] = a[x][x - y];\n        }\n    }\n    return b;\n}\n\nvector<Op> reflect_ops(vector<Op> ops) {\n    for (auto& op : ops) {\n        op.y1 = op.x1 - op.y1;\n        op.y2 = op.x2 - op.y2;\n    }\n    return ops;\n}\n\nbool better_candidate(const Candidate& a, const Candidate& b) {\n    if (a.score_like() != b.score_like()) return a.score_like() > b.score_like();\n    if (a.E != b.E) return a.E < b.E;\n    return a.ops.size() < b.ops.size();\n}\n\nvoid apply_ops(Board& b, const vector<Op>& ops) {\n    for (const auto& op : ops) {\n        swap(b[op.x1][op.y1], b[op.x2][op.y2]);\n    }\n}\n\nstruct COp {\n    Op op;\n    int a, b;\n};\n\ninline bool same_edge(const COp& p, const COp& q) {\n    return p.a == q.a && p.b == q.b;\n}\ninline bool disjoint_edges(const COp& p, const COp& q) {\n    return p.a != q.a && p.a != q.b && p.b != q.a && p.b != q.b;\n}\n\nvector<Op> compress_once(const vector<Op>& ops) {\n    vector<COp> st;\n    st.reserve(ops.size());\n    for (const auto& op : ops) {\n        int u = vid(op.x1, op.y1);\n        int v = vid(op.x2, op.y2);\n        if (u > v) swap(u, v);\n        st.push_back({op, u, v});\n        int i = (int)st.size() - 1;\n        while (i > 0) {\n            if (same_edge(st[i], st[i - 1])) {\n                st.erase(st.begin() + i - 1, st.begin() + i + 1);\n                break;\n            }\n            if (disjoint_edges(st[i], st[i - 1])) {\n                swap(st[i], st[i - 1]);\n                --i;\n            } else {\n                break;\n            }\n        }\n    }\n    vector<Op> res;\n    res.reserve(st.size());\n    for (auto& e : st) res.push_back(e.op);\n    return res;\n}\n\nvector<Op> compress_ops(vector<Op> ops) {\n    while (true) {\n        size_t before = ops.size();\n        ops = compress_once(ops);\n        if (ops.size() == before) break;\n    }\n    return ops;\n}\n\nCandidate normalize_candidate(const Board& init, Candidate c) {\n    c.ops = compress_ops(std::move(c.ops));\n    Board b = init;\n    apply_ops(b, c.ops);\n    c.E = count_violations(b);\n    return c;\n}\n\nbool valid_after_skipping_segment(const Board& init, const vector<Op>& ops, int l, int r) {\n    Board b = init;\n    for (int i = 0; i < l; ++i) {\n        const auto& op = ops[i];\n        swap(b[op.x1][op.y1], b[op.x2][op.y2]);\n    }\n    for (int i = r; i < (int)ops.size(); ++i) {\n        const auto& op = ops[i];\n        swap(b[op.x1][op.y1], b[op.x2][op.y2]);\n    }\n    return count_violations(b) == 0;\n}\n\nCandidate prune_candidate(const Board& init, Candidate cand, double limit_ms) {\n    if (cand.E != 0) return cand;\n    cand.ops = compress_ops(std::move(cand.ops));\n\n    for (int round = 0; round < 2; ++round) {\n        static const int BS[] = {256, 128, 64, 32, 16, 8, 4, 2, 1};\n        for (int bs : BS) {\n            if (elapsed_ms() > limit_ms) break;\n            int i = 0;\n            while (i < (int)cand.ops.size() && elapsed_ms() <= limit_ms) {\n                int r = min(i + bs, (int)cand.ops.size());\n                if (r <= i) break;\n                if (valid_after_skipping_segment(init, cand.ops, i, r)) {\n                    cand.ops.erase(cand.ops.begin() + i, cand.ops.begin() + r);\n                } else {\n                    i += bs;\n                }\n            }\n        }\n        if (elapsed_ms() > limit_ms) break;\n        cand.ops = compress_ops(std::move(cand.ops));\n    }\n\n    Board b = init;\n    apply_ops(b, cand.ops);\n    cand.E = count_violations(b);\n    return cand;\n}\n\n/* ---------------- fallback constructive family ---------------- */\n\nstruct Builder {\n    Board a;\n    vector<Op> ops;\n\n    Builder(const Board& init) : a(init) {\n        ops.reserve(10000);\n    }\n\n    static bool reachable_down(int r, int c, int tr, int tc) {\n        if (r > tr) return false;\n        return (c <= tc && tc <= c + (tr - r));\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        swap(a[x1][y1], a[x2][y2]);\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    pair<int,int> find_min_subtriangle(int x, int y) const {\n        int best_v = INT_MAX;\n        pair<int,int> best = {x, y};\n        for (int i = x; i < N; ++i) {\n            int l = y;\n            int r = y + (i - x);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] < best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    pair<int,int> find_max_uppertriangle(int x, int y) const {\n        int best_v = -1;\n        pair<int,int> best = {x, y};\n        for (int i = 0; i <= x; ++i) {\n            int l = max(0, y - (x - i));\n            int r = min(i, y);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] > best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_best_path_top(int tx, int ty, int sx, int sy) const {\n        const int NEG = -1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) dp[i][j] = NEG;\n\n        dp[sx][sy] = 0;\n        for (int r = sx - 1; r >= tx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, sx, sy)) continue;\n                int best = NEG;\n                if (reachable_down(r + 1, c, sx, sy) && dp[r + 1][c] != NEG)\n                    best = max(best, dp[r + 1][c]);\n                if (reachable_down(r + 1, c + 1, sx, sy) && dp[r + 1][c + 1] != NEG)\n                    best = max(best, dp[r + 1][c + 1]);\n                if (best != NEG) dp[r][c] = a[r][c] + best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = tx, c = ty;\n        path.push_back({r, c});\n        while (!(r == sx && c == sy)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = NEG;\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, sx, sy)) return;\n                if (dp[nr][nc] == NEG) return;\n                if (nxt.first == -1 || dp[nr][nc] > best ||\n                    (dp[nr][nc] == best && a[nr][nc] > a[nxt.first][nxt.second])) {\n                    best = dp[nr][nc];\n                    nxt = {nr, nc};\n                }\n            };\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back({r, c});\n        }\n        return path;\n    }\n\n    vector<pair<int,int>> build_best_path_bottom(int sx, int sy, int tx, int ty) const {\n        const int INF = 1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) dp[i][j] = INF;\n\n        dp[tx][ty] = 0;\n        for (int r = tx - 1; r >= sx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, tx, ty)) continue;\n                int best = INF;\n                if (reachable_down(r + 1, c, tx, ty) && dp[r + 1][c] != INF)\n                    best = min(best, a[r + 1][c] + dp[r + 1][c]);\n                if (reachable_down(r + 1, c + 1, tx, ty) && dp[r + 1][c + 1] != INF)\n                    best = min(best, a[r + 1][c + 1] + dp[r + 1][c + 1]);\n                dp[r][c] = best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = sx, c = sy;\n        path.push_back({r, c});\n        while (!(r == tx && c == ty)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = INF;\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, tx, ty)) return;\n                if (dp[nr][nc] == INF) return;\n                int cand = a[nr][nc] + dp[nr][nc];\n                if (nxt.first == -1 || cand < best ||\n                    (cand == best && a[nr][nc] < a[nxt.first][nxt.second])) {\n                    best = cand;\n                    nxt = {nr, nc};\n                }\n            };\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back({r, c});\n        }\n        return path;\n    }\n\n    Candidate solve_topdown() {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_min_subtriangle(x, y);\n                auto path = build_best_path_top(x, y, sx, sy);\n                for (int i = (int)path.size() - 1; i >= 1; --i) {\n                    auto [x1, y1] = path[i];\n                    auto [x2, y2] = path[i - 1];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n\n    Candidate solve_bottomup() {\n        for (int x = N - 1; x >= 0; --x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_max_uppertriangle(x, y);\n                auto path = build_best_path_bottom(sx, sy, x, y);\n                for (int i = 1; i < (int)path.size(); ++i) {\n                    auto [x1, y1] = path[i - 1];\n                    auto [x2, y2] = path[i];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\nCandidate solve_builder_top(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_topdown();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nCandidate solve_builder_bottom(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_bottomup();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\n/* ---------------- monotone range-based family ---------------- */\n\nstruct ValueParams {\n    ll W;\n    ll coef_value;\n    ll coef_mis;\n    int noise_id;\n};\n\nenum class Policy {\n    PURE_LOW,\n    PURE_HIGH,\n    GREEDY_LEN,\n    GREEDY_OBJ,\n    ALT_LOW,\n    ALT_HIGH\n};\n\nstruct PathInfo {\n    vector<pair<int,int>> path;\n    int len = (int)1e9;\n    ll obj = (1LL << 60);\n    bool valid = false;\n};\n\nstruct RangeSolver {\n    Board a;\n    array<int, M> posx{}, posy{};\n    vector<Op> ops;\n    ValueParams prm;\n\n    int lo = 0, hi = M - 1;\n    int curv = 0;\n\n    static constexpr ll INF = (1LL << 60);\n\n    ll memo[N][N];\n    bool seen[N][N];\n    int nxtx[N][N], nxty[N][N];\n\n    RangeSolver(const Board& init, ValueParams p) : a(init), prm(p) {\n        ops.reserve(10000);\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                int v = a[x][y];\n                posx[v] = x;\n                posy[v] = y;\n            }\n        }\n    }\n\n    inline ll noise_at(int x, int y) const {\n        if (prm.noise_id < 0) return 0;\n        return noise_tbl[prm.noise_id][x][y];\n    }\n\n    inline ll reward_up(int px, int py) const {\n        int t = a[px][py];\n        int before = abs(px - desired_row[t]);\n        int after = abs((px + 1) - desired_row[t]);\n        int delta = after - before;\n        return prm.coef_value * t - prm.coef_mis * delta + noise_at(px, py);\n    }\n\n    inline ll penalty_down(int cx, int cy) const {\n        int t = a[cx][cy];\n        int before = abs(cx - desired_row[t]);\n        int after = abs((cx - 1) - desired_row[t]);\n        int delta = after - before;\n        return prm.coef_value * t + prm.coef_mis * delta + noise_at(cx, cy);\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        int v1 = a[x1][y1];\n        int v2 = a[x2][y2];\n        swap(a[x1][y1], a[x2][y2]);\n        posx[v1] = x2; posy[v1] = y2;\n        posx[v2] = x1; posy[v2] = y1;\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    bool goal_up(int x, int y) const {\n        if (x == 0) return true;\n        if (y > 0 && a[x - 1][y - 1] >= lo) return false;\n        if (y < x && a[x - 1][y] >= lo) return false;\n        return true;\n    }\n\n    bool goal_down(int x, int y) const {\n        if (x == N - 1) return true;\n        if (a[x + 1][y] <= hi) return false;\n        if (a[x + 1][y + 1] <= hi) return false;\n        return true;\n    }\n\n    ll dfs_up(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        ll bestReward = -(1LL << 60);\n\n        auto consider = [&](int px, int py) {\n            int t = a[px][py];\n            if (!(lo < t && t <= hi)) return;\n            ll sub = dfs_up(px, py);\n            if (sub >= INF / 4) return;\n            ll rew = reward_up(px, py);\n            ll cand = sub + prm.W - rew;\n            if (cand < best || (cand == best && (rew > bestReward ||\n                (rew == bestReward && py < by)))) {\n                best = cand;\n                bx = px; by = py;\n                bestReward = rew;\n            }\n        };\n\n        if (x > 0) {\n            if (y > 0) consider(x - 1, y - 1);\n            if (y < x) consider(x - 1, y);\n        }\n\n        if (goal_up(x, y)) {\n            if (0 < best || bx == -1) {\n                best = 0;\n                bx = by = -1;\n            }\n        }\n\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    ll dfs_down(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        ll bestPen = (1LL << 60);\n\n        auto consider = [&](int cx, int cy) {\n            int t = a[cx][cy];\n            if (!(lo <= t && t < hi)) return;\n            ll sub = dfs_down(cx, cy);\n            if (sub >= INF / 4) return;\n            ll pen = penalty_down(cx, cy);\n            ll cand = sub + prm.W + pen;\n            if (cand < best || (cand == best && (pen < bestPen ||\n                (pen == bestPen && cy < by)))) {\n                best = cand;\n                bx = cx; by = cy;\n                bestPen = pen;\n            }\n        };\n\n        if (x + 1 < N) {\n            consider(x + 1, y);\n            consider(x + 1, y + 1);\n        }\n\n        if (goal_down(x, y)) {\n            if (0 < best || bx == -1) {\n                best = 0;\n                bx = by = -1;\n            }\n        }\n\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    PathInfo get_low_path(int lo_, int hi_) {\n        lo = lo_;\n        hi = hi_;\n        curv = lo;\n        memset(seen, 0, sizeof(seen));\n        int x = posx[curv], y = posy[curv];\n        ll obj = dfs_up(x, y);\n\n        PathInfo res;\n        if (obj >= INF / 4) return res;\n        res.valid = true;\n        res.obj = obj;\n        res.path.push_back({x, y});\n        while (nxtx[x][y] != -1) {\n            int nx = nxtx[x][y], ny = nxty[x][y];\n            res.path.push_back({nx, ny});\n            x = nx; y = ny;\n        }\n        res.len = (int)res.path.size() - 1;\n        return res;\n    }\n\n    PathInfo get_high_path(int lo_, int hi_) {\n        lo = lo_;\n        hi = hi_;\n        curv = hi;\n        memset(seen, 0, sizeof(seen));\n        int x = posx[curv], y = posy[curv];\n        ll obj = dfs_down(x, y);\n\n        PathInfo res;\n        if (obj >= INF / 4) return res;\n        res.valid = true;\n        res.obj = obj;\n        res.path.push_back({x, y});\n        while (nxtx[x][y] != -1) {\n            int nx = nxtx[x][y], ny = nxty[x][y];\n            res.path.push_back({nx, ny});\n            x = nx; y = ny;\n        }\n        res.len = (int)res.path.size() - 1;\n        return res;\n    }\n\n    void apply_path(const vector<pair<int,int>>& path) {\n        for (int i = 0; i + 1 < (int)path.size(); ++i) {\n            auto [x1, y1] = path[i];\n            auto [x2, y2] = path[i + 1];\n            do_swap(x1, y1, x2, y2);\n        }\n    }\n\n    Candidate run(Policy policy) {\n        int l = 0, h = M - 1;\n        bool alt_take_low = (policy == Policy::ALT_LOW);\n\n        while (l <= h) {\n            if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n            bool take_low = false;\n\n            if (policy == Policy::PURE_LOW) {\n                take_low = true;\n            } else if (policy == Policy::PURE_HIGH) {\n                take_low = false;\n            } else if (policy == Policy::ALT_LOW || policy == Policy::ALT_HIGH) {\n                take_low = alt_take_low;\n            } else {\n                PathInfo up = get_low_path(l, h);\n                PathInfo dn = get_high_path(l, h);\n\n                if (!up.valid && !dn.valid) {\n                    return Candidate{ops, count_violations(a)};\n                } else if (!up.valid) {\n                    take_low = false;\n                } else if (!dn.valid) {\n                    take_low = true;\n                } else if (policy == Policy::GREEDY_LEN) {\n                    if (up.len != dn.len) take_low = up.len < dn.len;\n                    else if (up.obj != dn.obj) take_low = up.obj < dn.obj;\n                    else take_low = true;\n                } else {\n                    if (up.obj != dn.obj) take_low = up.obj < dn.obj;\n                    else if (up.len != dn.len) take_low = up.len < dn.len;\n                    else take_low = true;\n                }\n\n                if (take_low) {\n                    apply_path(up.path);\n                    ++l;\n                } else {\n                    apply_path(dn.path);\n                    --h;\n                }\n\n                if (policy == Policy::ALT_LOW || policy == Policy::ALT_HIGH) {\n                    alt_take_low = !alt_take_low;\n                }\n                continue;\n            }\n\n            if (take_low) {\n                PathInfo up = get_low_path(l, h);\n                if (!up.valid) return Candidate{ops, count_violations(a)};\n                apply_path(up.path);\n                ++l;\n            } else {\n                PathInfo dn = get_high_path(l, h);\n                if (!dn.valid) return Candidate{ops, count_violations(a)};\n                apply_path(dn.path);\n                --h;\n            }\n\n            if (policy == Policy::ALT_LOW || policy == Policy::ALT_HIGH) {\n                alt_take_low = !alt_take_low;\n            }\n        }\n\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\nCandidate solve_range(const Board& init, ValueParams prm, Policy policy, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    RangeSolver solver(b, prm);\n    Candidate c = solver.run(policy);\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\n/* ---------------- RNG ---------------- */\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed) : x(seed ? seed : 88172645463325252ULL) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    bool next_bool() {\n        return (next() >> 63) & 1;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    prepare_globals();\n\n    Board init{};\n    uint64_t seed = 0;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n            seed = splitmix64(seed ^ (uint64_t)(init[x][y] + 1009 * x + 65537 * y + 1));\n        }\n    }\n\n    g_start = chrono::steady_clock::now();\n\n    Candidate best = normalize_candidate(init, Candidate{{}, count_violations(init)});\n    vector<Candidate> pool;\n\n    auto add_pool = [&](const Candidate& c) {\n        if (c.E != 0 || (int)c.ops.size() > 10000) return;\n        pool.push_back(c);\n        sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.ops.size() != b.ops.size()) return a.ops.size() < b.ops.size();\n            return a.score_like() > b.score_like();\n        });\n        if ((int)pool.size() > 10) pool.pop_back();\n    };\n\n    auto consider = [&](Candidate cand) {\n        if ((int)cand.ops.size() > 10000) return;\n        if (best.E == 0 && cand.E == 0 && !best.ops.empty()) {\n            if ((int)cand.ops.size() >= (int)best.ops.size() + 80) return;\n        }\n        cand = normalize_candidate(init, std::move(cand));\n        add_pool(cand);\n        if (better_candidate(cand, best)) best = cand;\n    };\n\n    vector<ValueParams> params = {\n        {1000000000LL, 0,  0,  -1},\n        {950LL,        1,  0,  -1},\n        {850LL,        1,  0,  -1},\n        {750LL,        1,  4,  -1},\n        {650LL,        1,  8,  -1},\n        {550LL,        1, 12,  -1},\n        {450LL,        1, 16,  -1},\n        {380LL,        1, 20,  -1},\n        {320LL,        1, 24,  -1},\n        {280LL,        2, 16,  -1},\n        {450LL,        1, 16,   0},\n        {380LL,        1, 20,   1},\n        {320LL,        1, 24,   2},\n        {280LL,        2, 16,   3},\n    };\n\n    vector<Policy> policies = {\n        Policy::PURE_LOW,\n        Policy::PURE_HIGH,\n        Policy::GREEDY_LEN,\n        Policy::GREEDY_OBJ,\n        Policy::ALT_LOW,\n        Policy::ALT_HIGH\n    };\n\n    for (const auto& prm : params) {\n        for (bool refl : {false, true}) {\n            if (elapsed_ms() > 1150.0) break;\n            consider(solve_range(init, prm, Policy::PURE_LOW, refl));\n            if (elapsed_ms() > 1200.0) break;\n            consider(solve_range(init, prm, Policy::PURE_HIGH, refl));\n            if (elapsed_ms() > 1250.0) break;\n            consider(solve_range(init, prm, Policy::GREEDY_LEN, refl));\n            if (elapsed_ms() > 1300.0) break;\n            consider(solve_range(init, prm, Policy::GREEDY_OBJ, refl));\n        }\n        if (elapsed_ms() > 1350.0) break;\n    }\n\n    if (elapsed_ms() <= 1450.0) {\n        for (bool refl : {false, true}) {\n            consider(solve_range(init, {450LL, 1, 16, -1}, Policy::ALT_LOW, refl));\n            consider(solve_range(init, {450LL, 1, 16, -1}, Policy::ALT_HIGH, refl));\n            consider(solve_range(init, {320LL, 1, 24, 2}, Policy::ALT_LOW, refl));\n            consider(solve_range(init, {320LL, 1, 24, 2}, Policy::ALT_HIGH, refl));\n        }\n    }\n\n    if (elapsed_ms() <= 1520.0) consider(solve_builder_top(init, false));\n    if (elapsed_ms() <= 1560.0) consider(solve_builder_top(init, true));\n    if (elapsed_ms() <= 1600.0) consider(solve_builder_bottom(init, false));\n    if (elapsed_ms() <= 1640.0) consider(solve_builder_bottom(init, true));\n\n    XorShift64 rng(seed ^ 0x9e3779b97f4a7c15ULL);\n\n    static const ll Wlist[] = {\n        1000000000LL, 1000LL, 950LL, 900LL, 850LL, 800LL, 750LL,\n        700LL, 650LL, 600LL, 550LL, 500LL, 450LL, 420LL, 380LL,\n        350LL, 320LL, 300LL, 280LL, 260LL\n    };\n    static const ll CVlist[] = {0LL, 1LL, 1LL, 1LL, 2LL};\n    static const ll CMlist[] = {0LL, 4LL, 8LL, 12LL, 16LL, 20LL, 24LL, 28LL};\n\n    while (elapsed_ms() < 1680.0) {\n        ValueParams prm;\n        prm.W = Wlist[rng.next_int(0, (int)(sizeof(Wlist) / sizeof(Wlist[0])) - 1)];\n        prm.coef_value = CVlist[rng.next_int(0, (int)(sizeof(CVlist) / sizeof(CVlist[0])) - 1)];\n        prm.coef_mis = CMlist[rng.next_int(0, (int)(sizeof(CMlist) / sizeof(CMlist[0])) - 1)];\n        int z = rng.next_int(0, 19);\n        prm.noise_id = (z < 4 ? -1 : z - 4);\n\n        Policy pol = policies[rng.next_int(0, (int)policies.size() - 1)];\n        bool refl = rng.next_bool();\n        consider(solve_range(init, prm, pol, refl));\n    }\n\n    add_pool(best);\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.ops.size() != b.ops.size()) return a.ops.size() < b.ops.size();\n        return a.score_like() > b.score_like();\n    });\n\n    for (int i = 0; i < (int)pool.size() && elapsed_ms() < 1950.0; ++i) {\n        Candidate pruned = prune_candidate(init, pool[i], 1950.0);\n        pruned = normalize_candidate(init, std::move(pruned));\n        if (better_candidate(pruned, best)) best = std::move(pruned);\n    }\n\n    if ((int)best.ops.size() > 10000) {\n        best.ops.clear();\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& op : best.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick() : n(0) {}\n    Fenwick(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int r) const { // [0, r)\n        int s = 0;\n        for (; r > 0; r -= r & -r) s += bit[r];\n        return s;\n    }\n    int total() const { return sumPrefix(n); }\n};\n\nstruct Strategy {\n    int hmode; // peel-order heuristic\n    int smode; // choose mode\n};\n\nstruct PeelInfo {\n    array<int, 81> pos;\n    vector<int> safe0;\n};\n\nclass Solver {\n    static constexpr int V = 81;\n    int D, N, M;\n    int root;\n    array<char, V> obstacle{};\n    array<vector<int>, V> adj;\n    array<int, V> dist0{};\n    vector<int> cells; // non-obstacle, non-root cells\n\n    Strategy best_strategy{0, 0};\n    array<int, V> label{};\n\n    int id(int i, int j) const { return i * D + j; }\n\n    void build_adj() {\n        for (int v = 0; v < V; ++v) adj[v].clear();\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int u = id(i, j);\n                if (obstacle[u]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir], nj = j + dj[dir];\n                    if (ni < 0 || ni >= D || nj < 0 || nj >= D) continue;\n                    int v = id(ni, nj);\n                    if (obstacle[v]) continue;\n                    adj[u].push_back(v);\n                }\n            }\n        }\n    }\n\n    void bfs_dist(const array<char, V>& active, array<int, V>& dist) const {\n        dist.fill(-1);\n        queue<int> q;\n        if (!active[root]) return;\n        dist[root] = 0;\n        q.push(root);\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (!active[v] || dist[v] != -1) continue;\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n\n    void dfs_art(\n        int u, int p,\n        const array<char, V>& active,\n        array<int, V>& ord,\n        array<int, V>& low,\n        array<char, V>& arti,\n        int& timer\n    ) const {\n        ord[u] = low[u] = timer++;\n        int child = 0;\n        for (int v : adj[u]) {\n            if (!active[v]) continue;\n            if (ord[v] == -1) {\n                ++child;\n                dfs_art(v, u, active, ord, low, arti, timer);\n                low[u] = min(low[u], low[v]);\n                if (p != -1 && low[v] >= ord[u]) arti[u] = 1;\n            } else if (v != p) {\n                low[u] = min(low[u], ord[v]);\n            }\n        }\n        if (p == -1 && child > 1) arti[u] = 1;\n    }\n\n    void compute_articulation(const array<char, V>& active, array<char, V>& arti) const {\n        arti.fill(0);\n        array<int, V> ord, low;\n        ord.fill(-1);\n        low.fill(-1);\n        int timer = 0;\n        if (active[root]) dfs_art(root, -1, active, ord, low, arti, timer);\n    }\n\n    array<int, 4> make_key(\n        int v,\n        const array<int, V>& dist,\n        const array<int, V>& deg,\n        int hmode\n    ) const {\n        // Bigger key => removed earlier in canonical peel\n        if (hmode == 0) {\n            // Dynamic distance first\n            return {dist[v], -deg[v], dist0[v], -v};\n        } else if (hmode == 1) {\n            // Static distance first\n            return {dist0[v], -deg[v], dist[v], -v};\n        } else {\n            // Mixed\n            return {2 * dist[v] + dist0[v], -deg[v], dist[v], -v};\n        }\n    }\n\n    PeelInfo peel_info(const array<char, V>& occupied, const Strategy& st) const {\n        PeelInfo info;\n        info.pos.fill(-1);\n        info.safe0.clear();\n\n        array<char, V> active{};\n        active.fill(0);\n        active[root] = 1;\n        int rem = 0;\n        for (int v : cells) {\n            if (!occupied[v]) {\n                active[v] = 1;\n                ++rem;\n            }\n        }\n\n        for (int step = 0; step < rem; ++step) {\n            array<int, V> dist;\n            bfs_dist(active, dist);\n\n            array<char, V> arti;\n            compute_articulation(active, arti);\n\n            array<int, V> deg{};\n            deg.fill(0);\n            for (int u = 0; u < V; ++u) {\n                if (!active[u]) continue;\n                for (int v : adj[u]) if (active[v]) ++deg[u];\n            }\n\n            vector<int> safe;\n            int best = -1;\n            array<int, 4> bestKey{};\n\n            for (int v : cells) {\n                if (!active[v]) continue;\n                if (dist[v] == -1) continue; // should not happen\n                if (arti[v]) continue;\n                safe.push_back(v);\n                auto key = make_key(v, dist, deg, st.hmode);\n                if (best == -1 || key > bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n\n            if (step == 0) info.safe0 = safe;\n\n            if (best == -1) {\n                // Fallback; theoretically unnecessary\n                for (int v : cells) {\n                    if (active[v] && dist[v] != -1) {\n                        best = v;\n                        break;\n                    }\n                }\n                if (step == 0 && info.safe0.empty() && best != -1) {\n                    info.safe0.push_back(best);\n                }\n            }\n\n            if (best == -1) break;\n            info.pos[best] = step;\n            active[best] = 0;\n        }\n\n        return info;\n    }\n\n    int choose_cell(const array<char, V>& occupied, const Fenwick& unseen, int t, const Strategy& st) const {\n        int m = unseen.total();\n        int r = unseen.sumPrefix(t); // current label rank among unseen\n\n        PeelInfo info = peel_info(occupied, st);\n        vector<int> safe = info.safe0;\n\n        if (safe.empty()) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) if (!occupied[v]) return v;\n            return cells.front();\n        }\n\n        if (st.smode == 0) {\n            // Quantile among currently legal choices\n            sort(safe.begin(), safe.end(), [&](int a, int b) {\n                if (info.pos[a] != info.pos[b]) return info.pos[a] > info.pos[b];\n                return a < b;\n            });\n            int idx = (int)((long long)r * (int)safe.size() / m);\n            if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n            return safe[idx];\n        } else {\n            // Closest to absolute target position in canonical peel\n            int target = m - 1 - r; // large => early output\n            int best = -1;\n            pair<int, int> bestPair{INT_MAX, INT_MAX};\n            for (int v : safe) {\n                int d = abs(info.pos[v] - target);\n                int tie = (target * 2 >= m - 1) ? -info.pos[v] : info.pos[v];\n                pair<int, int> cur{d, tie};\n                if (best == -1 || cur < bestPair) {\n                    best = v;\n                    bestPair = cur;\n                }\n            }\n            return best;\n        }\n    }\n\n    int best_reachable_smallest(const array<char, V>& occ, const array<int, V>& lbl) const {\n        array<char, V> vis{};\n        vis.fill(0);\n        queue<int> q;\n        vis[root] = 1;\n        q.push(root);\n\n        int best = -1;\n\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (occ[v]) {\n                    if (best == -1 || lbl[v] < lbl[best]) best = v;\n                } else {\n                    if (!vis[v]) {\n                        vis[v] = 1;\n                        q.push(v);\n                    }\n                }\n            }\n        }\n\n        if (best == -1) {\n            // Fallback; theoretically unnecessary\n            for (int v : cells) {\n                if (occ[v] && (best == -1 || lbl[v] < lbl[best])) best = v;\n            }\n        }\n        return best;\n    }\n\n    long long simulate(const Strategy& st, const vector<int>& perm) const {\n        array<char, V> occ{};\n        occ.fill(0);\n        array<int, V> lbl;\n        lbl.fill(-1);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int x : perm) {\n            int c = choose_cell(occ, unseen, x, st);\n            occ[c] = 1;\n            lbl[c] = x;\n            unseen.add(x, -1);\n        }\n\n        array<char, V> curOcc = occ;\n        vector<int> out;\n        out.reserve(M);\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, lbl);\n            out.push_back(lbl[c]);\n            curOcc[c] = 0;\n        }\n\n        long long inv = 0;\n        for (int i = 0; i < M; ++i) {\n            for (int j = i + 1; j < M; ++j) {\n                if (out[i] > out[j]) ++inv;\n            }\n        }\n        return inv;\n    }\n\n    void train_best_strategy() {\n        vector<Strategy> cand = {\n            {0, 0}, {0, 1},\n            {1, 0}, {1, 1},\n            {2, 0}, {2, 1}\n        };\n\n        uint64_t seed = 1469598103934665603ULL;\n        seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n        for (int v = 0; v < V; ++v) {\n            if (obstacle[v]) {\n                seed ^= (uint64_t)(v + 1);\n                seed *= 1099511628211ULL;\n            }\n        }\n        mt19937_64 rng(seed);\n\n        const int TRAIN_ITERS = 4;\n        vector<vector<int>> perms(TRAIN_ITERS, vector<int>(M));\n        for (int it = 0; it < TRAIN_ITERS; ++it) {\n            iota(perms[it].begin(), perms[it].end(), 0);\n            shuffle(perms[it].begin(), perms[it].end(), rng);\n        }\n\n        long long bestScore = (1LL << 62);\n        for (const auto& st : cand) {\n            long long sumInv = 0;\n            for (int it = 0; it < TRAIN_ITERS; ++it) {\n                sumInv += simulate(st, perms[it]);\n            }\n            if (sumInv < bestScore) {\n                bestScore = sumInv;\n                best_strategy = st;\n            }\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> D >> N;\n        root = id(0, (D - 1) / 2);\n\n        obstacle.fill(0);\n        label.fill(-1);\n\n        for (int k = 0; k < N; ++k) {\n            int i, j;\n            cin >> i >> j;\n            obstacle[id(i, j)] = 1;\n        }\n\n        build_adj();\n\n        cells.clear();\n        for (int v = 0; v < V; ++v) {\n            if (!obstacle[v] && v != root) cells.push_back(v);\n        }\n        M = (int)cells.size();\n\n        // Original distances\n        array<char, V> active{};\n        active.fill(0);\n        for (int v = 0; v < V; ++v) if (!obstacle[v]) active[v] = 1;\n        bfs_dist(active, dist0);\n\n        train_best_strategy();\n\n        array<char, V> occupied{};\n        occupied.fill(0);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int d = 0; d < M; ++d) {\n            int t;\n            cin >> t;\n\n            int c = choose_cell(occupied, unseen, t, best_strategy);\n            occupied[c] = 1;\n            label[c] = t;\n            unseen.add(t, -1);\n\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            cout.flush();\n        }\n\n        array<char, V> curOcc = occupied;\n        for (int step = 0; step < M; ++step) {\n            int c = best_reachable_smallest(curOcc, label);\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            curOcc[c] = 0;\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXV = 2500;\nstatic constexpr int MAXC = 101;\nstatic constexpr int INF_INT = 1e9;\n\nint n, m;\nbool origAdj[MAXC][MAXC];\nint distColor[MAXC];\nint degColor[MAXC];\nvector<vector<int>> depthGroups;\n\nstruct Board {\n    int h = 0, w = 0;\n    array<unsigned char, MAXV> a{};\n    int nonzero = 0;\n    long long distsum = 0;\n};\n\ninline bool better_board(const Board& x, const Board& y) {\n    if (x.nonzero != y.nonzero) return x.nonzero < y.nonzero;\n    if (x.distsum != y.distsum) return x.distsum < y.distsum;\n    return x.h * x.w < y.h * y.w;\n}\n\ninline bool not_worse_board(const Board& x, const Board& y) {\n    return !better_board(y, x);\n}\n\nuint64_t hash_board(const Board& b) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)b.h + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    h ^= (uint64_t)b.w + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    int V = b.h * b.w;\n    for (int i = 0; i < V; ++i) {\n        h ^= (uint64_t)(b.a[i] + 1) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    }\n    return h;\n}\n\nvoid compute_stats(Board& b) {\n    b.nonzero = 0;\n    b.distsum = 0;\n    int V = b.h * b.w;\n    for (int i = 0; i < V; ++i) {\n        int c = b.a[i];\n        if (c != 0) ++b.nonzero;\n        b.distsum += distColor[c];\n    }\n}\n\ninline bool row_all_zero(const Board& b, int r) {\n    int base = r * b.w;\n    for (int j = 0; j < b.w; ++j) {\n        if (b.a[base + j] != 0) return false;\n    }\n    return true;\n}\n\ninline bool col_all_zero(const Board& b, int c) {\n    for (int i = 0; i < b.h; ++i) {\n        if (b.a[i * b.w + c] != 0) return false;\n    }\n    return true;\n}\n\nBoard delete_row_board(const Board& b, int r, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h - 1;\n    nb.w = b.w;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r) continue;\n        memcpy(&nb.a[p], &b.a[i * b.w], b.w * sizeof(unsigned char));\n        p += b.w;\n    }\n    return nb;\n}\n\nBoard delete_col_board(const Board& b, int c, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h;\n    nb.w = b.w - 1;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nBoard delete_rows2_board(const Board& b, int r1, int r2, int gainNz, long long gainDist) {\n    if (r1 > r2) swap(r1, r2);\n    Board nb;\n    nb.h = b.h - 2;\n    nb.w = b.w;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r1 || i == r2) continue;\n        memcpy(&nb.a[p], &b.a[i * b.w], b.w * sizeof(unsigned char));\n        p += b.w;\n    }\n    return nb;\n}\n\nBoard delete_cols2_board(const Board& b, int c1, int c2, int gainNz, long long gainDist) {\n    if (c1 > c2) swap(c1, c2);\n    Board nb;\n    nb.h = b.h;\n    nb.w = b.w - 2;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c1 || j == c2) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nBoard delete_rowcol_board(const Board& b, int r, int c, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h - 1;\n    nb.w = b.w - 1;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r) continue;\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nvoid crop_zero_border(Board& b) {\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        while (b.h > 1 && row_all_zero(b, 0)) {\n            b = delete_row_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.h > 1 && row_all_zero(b, b.h - 1)) {\n            b = delete_row_board(b, b.h - 1, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, 0)) {\n            b = delete_col_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, b.w - 1)) {\n            b = delete_col_board(b, b.w - 1, 0, 0);\n            changed = true;\n        }\n    }\n}\n\nint sparse_score(const Board& b) {\n    int r1 = INF_INT, r2 = INF_INT;\n    for (int i = 0; i < b.h; ++i) {\n        int cnt = 0;\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) cnt += (b.a[base + j] != 0);\n        if (cnt < r1) { r2 = r1; r1 = cnt; }\n        else if (cnt < r2) r2 = cnt;\n    }\n\n    int c1 = INF_INT, c2 = INF_INT;\n    for (int j = 0; j < b.w; ++j) {\n        int cnt = 0;\n        for (int i = 0; i < b.h; ++i) cnt += (b.a[i * b.w + j] != 0);\n        if (cnt < c1) { c2 = c1; c1 = cnt; }\n        else if (cnt < c2) c2 = cnt;\n    }\n\n    if (r1 == INF_INT) r1 = 0;\n    if (r2 == INF_INT) r2 = r1;\n    if (c1 == INF_INT) c1 = 0;\n    if (c2 == INF_INT) c2 = c1;\n    return r1 + r2 + c1 + c2;\n}\n\nbool is_legal(const Board& b) {\n    static int cnt[MAXC], firstPos[MAXC];\n    static bool adj[MAXC][MAXC];\n    static int vis[MAXV];\n    static int q[MAXV];\n    static int vis0[(MAXN + 2) * (MAXN + 2)];\n    static int q0[(MAXN + 2) * (MAXN + 2)];\n\n    memset(cnt, 0, sizeof(cnt));\n    memset(firstPos, -1, sizeof(firstPos));\n    memset(adj, 0, sizeof(adj));\n\n    int h = b.h, w = b.w;\n    int zeroCnt = 0;\n\n    for (int i = 0; i < h; ++i) {\n        int base = i * w;\n        for (int j = 0; j < w; ++j) {\n            int idx = base + j;\n            int c = b.a[idx];\n            if (c == 0) {\n                ++zeroCnt;\n            } else {\n                ++cnt[c];\n                if (firstPos[c] == -1) firstPos[c] = idx;\n            }\n\n            if ((i == 0 || i == h - 1 || j == 0 || j == w - 1) && c != 0) {\n                adj[c][0] = adj[0][c] = true;\n            }\n            if (i + 1 < h) {\n                int d = b.a[idx + w];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n            if (j + 1 < w) {\n                int d = b.a[idx + 1];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n        }\n    }\n\n    for (int c = 1; c <= m; ++c) {\n        if (cnt[c] == 0) return false;\n    }\n\n    for (int c = 0; c <= m; ++c) {\n        for (int d = 0; d <= m; ++d) {\n            if (adj[c][d] != origAdj[c][d]) return false;\n        }\n    }\n\n    memset(vis, 0, sizeof(vis));\n    int stamp = 1;\n\n    for (int color = 1; color <= m; ++color) {\n        if (cnt[color] <= 1) {\n            ++stamp;\n            continue;\n        }\n\n        int start = firstPos[color];\n        int ql = 0, qr = 0;\n        q[qr++] = start;\n        vis[start] = stamp;\n        int seen = 1;\n\n        while (ql < qr) {\n            int v = q[ql++];\n            int x = v / w, y = v % w;\n\n            if (x > 0) {\n                int to = v - w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (x + 1 < h && seen < cnt[color]) {\n                int to = v + w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (y > 0 && seen < cnt[color]) {\n                int to = v - 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (y + 1 < w && seen < cnt[color]) {\n                int to = v + 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n        }\n\n        if (seen != cnt[color]) return false;\n        ++stamp;\n    }\n\n    if (zeroCnt > 0) {\n        int H = h + 2, W = w + 2;\n        memset(vis0, 0, sizeof(vis0));\n        int ql = 0, qr = 0;\n        q0[qr++] = 0;\n        vis0[0] = 1;\n        int reachedZero = 0;\n\n        auto can_pass = [&](int r, int c) -> bool {\n            if (r < 0 || r >= H || c < 0 || c >= W) return false;\n            int id = r * W + c;\n            if (vis0[id]) return false;\n            if (r == 0 || r == H - 1 || c == 0 || c == W - 1) return true;\n            return b.a[(r - 1) * w + (c - 1)] == 0;\n        };\n\n        while (ql < qr) {\n            int v = q0[ql++];\n            int r = v / W, c = v % W;\n            static const int dr[4] = {-1, 1, 0, 0};\n            static const int dc[4] = {0, 0, -1, 1};\n            for (int k = 0; k < 4; ++k) {\n                int nr = r + dr[k], nc = c + dc[k];\n                if (!can_pass(nr, nc)) continue;\n                int nid = nr * W + nc;\n                vis0[nid] = 1;\n                q0[qr++] = nid;\n                if (1 <= nr && nr <= h && 1 <= nc && nc <= w) ++reachedZero;\n            }\n        }\n\n        if (reachedZero != zeroCnt) return false;\n    }\n\n    return true;\n}\n\nstruct ShrinkCand {\n    Board nb;\n    int sparse = 0;\n};\n\nstruct LineInfo {\n    int nz;\n    long long dist;\n    int idx;\n};\n\nBoard shrink_pass(Board b, mt19937& rng, Clock::time_point deadline, int randomTopK) {\n    crop_zero_border(b);\n    compute_stats(b);\n\n    static constexpr int PAIR_TOP = 5;\n    static constexpr int CROSS_TOP = 4;\n\n    auto add_candidate = [&](vector<ShrinkCand>& cands, Board&& nb) {\n        crop_zero_border(nb);\n        if (!is_legal(nb)) return;\n        ShrinkCand sc;\n        sc.nb = nb;\n        sc.sparse = sparse_score(nb);\n        cands.push_back(std::move(sc));\n    };\n\n    while (Clock::now() < deadline) {\n        vector<int> rowNz(b.h, 0), colNz(b.w, 0);\n        vector<long long> rowDist(b.h, 0), colDist(b.w, 0);\n\n        for (int i = 0; i < b.h; ++i) {\n            int base = i * b.w;\n            for (int j = 0; j < b.w; ++j) {\n                int c = b.a[base + j];\n                rowNz[i] += (c != 0);\n                colNz[j] += (c != 0);\n                rowDist[i] += distColor[c];\n                colDist[j] += distColor[c];\n            }\n        }\n\n        vector<ShrinkCand> cands;\n        cands.reserve(b.h + b.w + 48);\n        int bestSingleNZ = b.nonzero;\n\n        // Single deletions first.\n        if (b.h > 1) {\n            for (int r = 0; r < b.h; ++r) {\n                if ((r & 7) == 0 && Clock::now() >= deadline) return b;\n                Board nb = delete_row_board(b, r, rowNz[r], rowDist[r]);\n                crop_zero_border(nb);\n                if (!is_legal(nb)) continue;\n                ShrinkCand sc;\n                sc.nb = nb;\n                sc.sparse = sparse_score(nb);\n                bestSingleNZ = min(bestSingleNZ, nb.nonzero);\n                cands.push_back(std::move(sc));\n            }\n        }\n        if (b.w > 1) {\n            for (int c = 0; c < b.w; ++c) {\n                if ((c & 7) == 0 && Clock::now() >= deadline) return b;\n                Board nb = delete_col_board(b, c, colNz[c], colDist[c]);\n                crop_zero_border(nb);\n                if (!is_legal(nb)) continue;\n                ShrinkCand sc;\n                sc.nb = nb;\n                sc.sparse = sparse_score(nb);\n                bestSingleNZ = min(bestSingleNZ, nb.nonzero);\n                cands.push_back(std::move(sc));\n            }\n        }\n\n        // Macro escape only when singles don't directly improve score.\n        if (cands.empty() || bestSingleNZ >= b.nonzero) {\n            vector<LineInfo> rows, cols;\n            rows.reserve(b.h);\n            cols.reserve(b.w);\n            for (int i = 0; i < b.h; ++i) rows.push_back({rowNz[i], rowDist[i], i});\n            for (int j = 0; j < b.w; ++j) cols.push_back({colNz[j], colDist[j], j});\n\n            shuffle(rows.begin(), rows.end(), rng);\n            shuffle(cols.begin(), cols.end(), rng);\n\n            stable_sort(rows.begin(), rows.end(), [](const LineInfo& a, const LineInfo& b) {\n                if (a.nz != b.nz) return a.nz < b.nz;\n                if (a.dist != b.dist) return a.dist < b.dist;\n                return a.idx < b.idx;\n            });\n            stable_sort(cols.begin(), cols.end(), [](const LineInfo& a, const LineInfo& b) {\n                if (a.nz != b.nz) return a.nz < b.nz;\n                if (a.dist != b.dist) return a.dist < b.dist;\n                return a.idx < b.idx;\n            });\n\n            int rt = min<int>(PAIR_TOP, (int)rows.size());\n            int ct = min<int>(PAIR_TOP, (int)cols.size());\n\n            if (b.h > 2) {\n                for (int i = 0; i < rt; ++i) {\n                    for (int j = i + 1; j < rt; ++j) {\n                        if (((i * rt + j) & 15) == 0 && Clock::now() >= deadline) return b;\n                        int r1 = rows[i].idx, r2 = rows[j].idx;\n                        Board nb = delete_rows2_board(\n                            b, r1, r2,\n                            rowNz[r1] + rowNz[r2],\n                            rowDist[r1] + rowDist[r2]\n                        );\n                        add_candidate(cands, std::move(nb));\n                    }\n                }\n            }\n\n            if (b.w > 2) {\n                for (int i = 0; i < ct; ++i) {\n                    for (int j = i + 1; j < ct; ++j) {\n                        if (((i * ct + j) & 15) == 0 && Clock::now() >= deadline) return b;\n                        int c1 = cols[i].idx, c2 = cols[j].idx;\n                        Board nb = delete_cols2_board(\n                            b, c1, c2,\n                            colNz[c1] + colNz[c2],\n                            colDist[c1] + colDist[c2]\n                        );\n                        add_candidate(cands, std::move(nb));\n                    }\n                }\n            }\n\n            if (b.h > 1 && b.w > 1) {\n                rt = min<int>(CROSS_TOP, (int)rows.size());\n                ct = min<int>(CROSS_TOP, (int)cols.size());\n                for (int i = 0; i < rt; ++i) {\n                    for (int j = 0; j < ct; ++j) {\n                        if (((i * ct + j) & 15) == 0 && Clock::now() >= deadline) return b;\n                        int r = rows[i].idx, c = cols[j].idx;\n                        int cell = b.a[r * b.w + c];\n                        int gainNz = rowNz[r] + colNz[c] - (cell != 0);\n                        long long gainDist = rowDist[r] + colDist[c] - distColor[cell];\n                        Board nb = delete_rowcol_board(b, r, c, gainNz, gainDist);\n                        add_candidate(cands, std::move(nb));\n                    }\n                }\n            }\n        }\n\n        if (cands.empty()) break;\n\n        sort(cands.begin(), cands.end(), [](const ShrinkCand& x, const ShrinkCand& y) {\n            if (x.nb.nonzero != y.nb.nonzero) return x.nb.nonzero < y.nb.nonzero;\n            if (x.sparse != y.sparse) return x.sparse < y.sparse;\n            int ax = x.nb.h * x.nb.w, ay = y.nb.h * y.nb.w;\n            if (ax != ay) return ax < ay;\n            if (x.nb.distsum != y.nb.distsum) return x.nb.distsum < y.nb.distsum;\n            return false;\n        });\n\n        int lim = min<int>((int)cands.size(), max(1, randomTopK));\n        int pick = 0;\n        if (lim > 1) {\n            int a = uniform_int_distribution<int>(0, lim - 1)(rng);\n            int bb = uniform_int_distribution<int>(0, lim - 1)(rng);\n            pick = min(a, bb);\n        }\n\n        b = cands[pick].nb;\n        crop_zero_border(b);\n    }\n\n    return b;\n}\n\nstruct LSState {\n    int h = 0, w = 0, V = 0;\n    array<unsigned char, MAXV> g{};\n    array<int, MAXC> cnt{};\n    int edge[MAXC][MAXC];\n    long long distSum = 0;\n    int nonzero = 0;\n\n    array<array<short, 4>, MAXV> nbr{};\n    array<unsigned char, MAXV> nbrCnt{};\n    array<unsigned char, MAXV> bside{};\n\n    int rowNZ[MAXN]{};\n    int colNZ[MAXN]{};\n};\n\nLSState build_state(const Board& b) {\n    LSState st;\n    st.h = b.h;\n    st.w = b.w;\n    st.V = b.h * b.w;\n    st.cnt.fill(0);\n    memset(st.edge, 0, sizeof(st.edge));\n    memset(st.rowNZ, 0, sizeof(st.rowNZ));\n    memset(st.colNZ, 0, sizeof(st.colNZ));\n    st.distSum = 0;\n    st.nonzero = 0;\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = b.a[idx];\n        st.g[idx] = b.a[idx];\n        ++st.cnt[c];\n        st.distSum += distColor[c];\n        if (c != 0) {\n            ++st.nonzero;\n            ++st.rowNZ[idx / st.w];\n            ++st.colNZ[idx % st.w];\n        }\n    }\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int i = idx / st.w, j = idx % st.w;\n        int k = 0;\n        if (i > 0) st.nbr[idx][k++] = idx - st.w;\n        if (i + 1 < st.h) st.nbr[idx][k++] = idx + st.w;\n        if (j > 0) st.nbr[idx][k++] = idx - 1;\n        if (j + 1 < st.w) st.nbr[idx][k++] = idx + 1;\n        st.nbrCnt[idx] = (unsigned char)k;\n        st.bside[idx] = (unsigned char)((i == 0) + (i == st.h - 1) + (j == 0) + (j == st.w - 1));\n    }\n\n    auto add_edge = [&](int a, int b, int delta) {\n        if (a == b) return;\n        st.edge[a][b] += delta;\n        st.edge[b][a] += delta;\n    };\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = st.g[idx];\n        int i = idx / st.w, j = idx % st.w;\n        if (i == 0) add_edge(c, 0, 1);\n        if (i == st.h - 1) add_edge(c, 0, 1);\n        if (j == 0) add_edge(c, 0, 1);\n        if (j == st.w - 1) add_edge(c, 0, 1);\n        if (i + 1 < st.h) add_edge(c, st.g[idx + st.w], 1);\n        if (j + 1 < st.w) add_edge(c, st.g[idx + 1], 1);\n    }\n\n    return st;\n}\n\nstatic int conn_vis[MAXV];\nstatic int conn_stamp = 1;\n\nbool connected_after_remove(const LSState& st, int color, int remIdx, int need, int startIdx) {\n    ++conn_stamp;\n    if (conn_stamp == INT_MAX) {\n        memset(conn_vis, 0, sizeof(conn_vis));\n        conn_stamp = 1;\n    }\n\n    static int q[MAXV];\n    int ql = 0, qr = 0;\n    q[qr++] = startIdx;\n    conn_vis[startIdx] = conn_stamp;\n    int seen = 1;\n\n    while (ql < qr) {\n        int v = q[ql++];\n        int deg = st.nbrCnt[v];\n        for (int k = 0; k < deg; ++k) {\n            int to = st.nbr[v][k];\n            if (to == remIdx) continue;\n            if (st.g[to] != color) continue;\n            if (conn_vis[to] == conn_stamp) continue;\n            conn_vis[to] = conn_stamp;\n            q[qr++] = to;\n            if (++seen == need) return true;\n        }\n    }\n    return seen == need;\n}\n\ninline bool can_to_zero(const LSState& st, int idx) {\n    if (st.bside[idx] > 0) return true;\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        if (st.g[st.nbr[idx][k]] == 0) return true;\n    }\n    return false;\n}\n\nvoid compute_zero_dist(const LSState& st, vector<int>& zd) {\n    zd.assign(st.V, INF_INT);\n    static int q[MAXV];\n    int ql = 0, qr = 0;\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        if (st.g[idx] == 0 || can_to_zero(st, idx)) {\n            zd[idx] = 0;\n            q[qr++] = idx;\n        }\n    }\n\n    while (ql < qr) {\n        int v = q[ql++];\n        int nd = zd[v] + 1;\n        int deg = st.nbrCnt[v];\n        for (int k = 0; k < deg; ++k) {\n            int to = st.nbr[v][k];\n            if (zd[to] > nd) {\n                zd[to] = nd;\n                q[qr++] = to;\n            }\n        }\n    }\n}\n\nbool try_move(LSState& st, int idx, int t) {\n    int c = st.g[idx];\n    if (c == 0 || c == t) return false;\n    if (st.cnt[c] <= 1) return false;\n\n    int sameNbr = 0;\n    int startIdx = -1;\n    bool targetConnected = false;\n\n    if (t == 0 && st.bside[idx] > 0) targetConnected = true;\n\n    int pa[12], pb[12], pd[12];\n    int pnum = 0;\n\n    auto add_change = [&](int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < pnum; ++i) {\n            if (pa[i] == a && pb[i] == b) {\n                pd[i] += d;\n                return;\n            }\n        }\n        pa[pnum] = a;\n        pb[pnum] = b;\n        pd[pnum] = d;\n        ++pnum;\n    };\n\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        int to = st.nbr[idx][k];\n        int d = st.g[to];\n\n        if (d == c) {\n            ++sameNbr;\n            startIdx = to;\n        }\n        if (d == t) targetConnected = true;\n        if (t == 0 && d == 0) targetConnected = true;\n\n        if (c != d) add_change(c, d, -1);\n        if (t != d) add_change(t, d, +1);\n    }\n\n    if (st.bside[idx] > 0) {\n        add_change(c, 0, -st.bside[idx]);\n        add_change(t, 0, +st.bside[idx]);\n    }\n\n    if (!targetConnected) return false;\n    if (sameNbr == 0) return false;\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        int nc = st.edge[a][b] + pd[i];\n        if (nc < 0) return false;\n        bool nadj = (nc > 0);\n        if (nadj != origAdj[a][b]) return false;\n    }\n\n    if (sameNbr >= 2) {\n        if (!connected_after_remove(st, c, idx, st.cnt[c] - 1, startIdx)) return false;\n    }\n\n    st.g[idx] = (unsigned char)t;\n    --st.cnt[c];\n    ++st.cnt[t];\n    st.distSum += (long long)distColor[t] - distColor[c];\n\n    if (t == 0) {\n        --st.nonzero;\n        --st.rowNZ[idx / st.w];\n        --st.colNZ[idx % st.w];\n    }\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        st.edge[a][b] += pd[i];\n        st.edge[b][a] += pd[i];\n    }\n\n    return true;\n}\n\narray<int, MAXC> make_key(const LSState& st, mt19937& rng) {\n    array<int, MAXC> key{};\n    key.fill(0);\n    key[0] = 0;\n\n    for (int d = 1; d < (int)depthGroups.size(); ++d) {\n        vector<int> v = depthGroups[d];\n        shuffle(v.begin(), v.end(), rng);\n        stable_sort(v.begin(), v.end(), [&](int a, int b) {\n            if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n            if (degColor[a] != degColor[b]) return degColor[a] > degColor[b];\n            return a < b;\n        });\n        for (int i = 0; i < (int)v.size(); ++i) {\n            key[v[i]] = d * 1000 + (i + 1);\n        }\n    }\n    return key;\n}\n\nbool attempt_best_move(LSState& st, int idx, const array<int, MAXC>& key, bool permissive_same_depth) {\n    int c = st.g[idx];\n    if (c == 0) return false;\n\n    int cand[5];\n    int ccnt = 0;\n\n    auto add_cand = [&](int x) {\n        if (x == c) return;\n\n        if (x != 0) {\n            if (distColor[x] > distColor[c]) return;\n\n            if (distColor[x] == distColor[c]) {\n                if (!permissive_same_depth) {\n                    if (key[x] >= key[c]) return;\n                } else {\n                    if (st.cnt[x] < st.cnt[c]) return;\n                    if (st.cnt[x] == st.cnt[c] && key[x] >= key[c]) return;\n                }\n            }\n        }\n\n        for (int i = 0; i < ccnt; ++i) {\n            if (cand[i] == x) return;\n        }\n        cand[ccnt++] = x;\n    };\n\n    if (can_to_zero(st, idx)) add_cand(0);\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) add_cand(st.g[st.nbr[idx][k]]);\n\n    sort(cand, cand + ccnt, [&](int a, int b) {\n        if (a == 0 || b == 0) return a == 0;\n        if (distColor[a] != distColor[b]) return distColor[a] < distColor[b];\n        if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n        if (key[a] != key[b]) return key[a] < key[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < ccnt; ++i) {\n        if (try_move(st, idx, cand[i])) return true;\n    }\n    return false;\n}\n\nbool global_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n    vector<int> zeroDist;\n    compute_zero_dist(st, zeroDist);\n\n    vector<int> ord(st.V);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n\n    stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int ca = st.g[a], cb = st.g[b];\n        if (ca == 0 || cb == 0) return ca != 0;\n\n        if (zeroDist[a] != zeroDist[b]) return zeroDist[a] < zeroDist[b];\n\n        int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n        int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n        if (ma != mb) return ma < mb;\n\n        if (distColor[ca] != distColor[cb]) return distColor[ca] > distColor[cb];\n        if (key[ca] != key[cb]) return key[ca] > key[cb];\n\n        int sa = st.rowNZ[a / st.w] + st.colNZ[a % st.w];\n        int sb = st.rowNZ[b / st.w] + st.colNZ[b % st.w];\n        return sa < sb;\n    });\n\n    bool moved = false;\n    for (int it = 0; it < st.V; ++it) {\n        if ((it & 255) == 0 && Clock::now() >= deadline) break;\n        int idx = ord[it];\n        if (attempt_best_move(st, idx, key, false)) moved = true;\n    }\n    return moved;\n}\n\nbool line_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n    vector<int> zeroDist;\n    compute_zero_dist(st, zeroDist);\n\n    vector<pair<int, int>> lines;\n    lines.reserve(st.h + st.w);\n    for (int i = 0; i < st.h; ++i) if (st.rowNZ[i] > 0) lines.push_back({st.rowNZ[i], i});\n    for (int j = 0; j < st.w; ++j) if (st.colNZ[j] > 0) lines.push_back({st.colNZ[j], st.h + j});\n\n    if (lines.empty()) return false;\n\n    shuffle(lines.begin(), lines.end(), rng);\n    stable_sort(lines.begin(), lines.end(), [](const auto& a, const auto& b) {\n        return a.first < b.first;\n    });\n\n    int L = min<int>((int)lines.size(), 8);\n    bool moved = false;\n\n    for (int li = 0; li < L; ++li) {\n        if ((li & 3) == 0 && Clock::now() >= deadline) break;\n\n        int code = lines[li].second;\n        vector<int> cells;\n\n        if (code < st.h) {\n            int r = code;\n            cells.reserve(st.rowNZ[r]);\n            for (int j = 0; j < st.w; ++j) {\n                int idx = r * st.w + j;\n                if (st.g[idx] != 0) cells.push_back(idx);\n            }\n        } else {\n            int c = code - st.h;\n            cells.reserve(st.colNZ[c]);\n            for (int i = 0; i < st.h; ++i) {\n                int idx = i * st.w + c;\n                if (st.g[idx] != 0) cells.push_back(idx);\n            }\n        }\n\n        shuffle(cells.begin(), cells.end(), rng);\n        stable_sort(cells.begin(), cells.end(), [&](int a, int b) {\n            if (zeroDist[a] != zeroDist[b]) return zeroDist[a] < zeroDist[b];\n\n            int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n            int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n            if (ma != mb) return ma < mb;\n\n            int da = distColor[st.g[a]], db = distColor[st.g[b]];\n            if (da != db) return da > db;\n\n            if (st.cnt[st.g[a]] != st.cnt[st.g[b]]) return st.cnt[st.g[a]] < st.cnt[st.g[b]];\n            int ka = key[st.g[a]], kb = key[st.g[b]];\n            if (ka != kb) return ka > kb;\n\n            return false;\n        });\n\n        for (int idx : cells) {\n            if (Clock::now() >= deadline) break;\n            if (attempt_best_move(st, idx, key, true)) moved = true;\n        }\n    }\n\n    return moved;\n}\n\nbool frontier_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n    vector<int> zeroDist;\n    compute_zero_dist(st, zeroDist);\n\n    vector<int> ord;\n    ord.reserve(st.V);\n    for (int idx = 0; idx < st.V; ++idx) {\n        if (st.g[idx] == 0) continue;\n        if (zeroDist[idx] <= 2) ord.push_back(idx);\n    }\n    if (ord.empty()) return false;\n\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (zeroDist[a] != zeroDist[b]) return zeroDist[a] < zeroDist[b];\n\n        int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n        int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n        if (ma != mb) return ma < mb;\n\n        int ca = st.g[a], cb = st.g[b];\n        if (distColor[ca] != distColor[cb]) return distColor[ca] > distColor[cb];\n        if (st.cnt[ca] != st.cnt[cb]) return st.cnt[ca] < st.cnt[cb];\n        if (key[ca] != key[cb]) return key[ca] > key[cb];\n\n        return false;\n    });\n\n    bool moved = false;\n    int lim = min<int>((int)ord.size(), 500);\n    for (int it = 0; it < lim; ++it) {\n        if ((it & 255) == 0 && Clock::now() >= deadline) break;\n        int idx = ord[it];\n        if (attempt_best_move(st, idx, key, false)) moved = true;\n    }\n    return moved;\n}\n\nvoid optimize(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    int stagnation = 0;\n    int phase = 0;\n\n    while (Clock::now() < deadline && stagnation < 6) {\n        bool moved = false;\n\n        int mode = phase & 3;\n        if (mode == 0 || mode == 3) moved = global_round(st, rng, deadline);\n        else if (mode == 1) moved = line_round(st, rng, deadline);\n        else moved = frontier_round(st, rng, deadline);\n\n        if (!moved && Clock::now() < deadline) {\n            moved = frontier_round(st, rng, deadline);\n        }\n        if (!moved && Clock::now() < deadline) {\n            moved = line_round(st, rng, deadline);\n        }\n\n        if (moved) stagnation = 0;\n        else ++stagnation;\n        ++phase;\n    }\n}\n\nBoard state_to_board(const LSState& st) {\n    Board b;\n    b.h = st.h;\n    b.w = st.w;\n    b.nonzero = st.nonzero;\n    b.distsum = st.distSum;\n    for (int i = 0; i < st.V; ++i) b.a[i] = st.g[i];\n    return b;\n}\n\nBoard shave_pass(Board b, mt19937& rng, Clock::time_point deadline) {\n    crop_zero_border(b);\n    compute_stats(b);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(16);\n    seen.insert(hash_board(b));\n\n    int stagnation = 0;\n\n    while (Clock::now() < deadline && stagnation < 3) {\n        auto now = Clock::now();\n        auto rem_ms = chrono::duration_cast<chrono::milliseconds>(deadline - now).count();\n        int slice = (int)max<long long>(20, rem_ms / 2);\n        auto inner_deadline = min(deadline, now + chrono::milliseconds(slice));\n\n        LSState st = build_state(b);\n        optimize(st, rng, inner_deadline);\n        Board nb = state_to_board(st);\n        crop_zero_border(nb);\n        compute_stats(nb);\n\n        uint64_t h = hash_board(nb);\n        if (better_board(nb, b) || (not_worse_board(nb, b) && !seen.count(h))) {\n            b = nb;\n            seen.insert(h);\n            stagnation = 0;\n        } else {\n            ++stagnation;\n        }\n    }\n\n    return b;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n >> m;\n\n    Board original;\n    original.h = n;\n    original.w = n;\n\n    uint64_t seed64 = 1234567891234567ULL;\n    for (int i = 0; i < n * n; ++i) {\n        int x;\n        cin >> x;\n        original.a[i] = (unsigned char)x;\n        seed64 ^= (uint64_t)(x + 1) + 0x9e3779b97f4a7c15ULL + (seed64 << 6) + (seed64 >> 2);\n    }\n\n    memset(origAdj, 0, sizeof(origAdj));\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int idx = i * n + j;\n            int c = original.a[idx];\n\n            if (i == 0 || i == n - 1 || j == 0 || j == n - 1) {\n                origAdj[c][0] = origAdj[0][c] = true;\n            }\n            if (i + 1 < n) {\n                int d = original.a[idx + n];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n            if (j + 1 < n) {\n                int d = original.a[idx + 1];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n        }\n    }\n\n    for (int i = 0; i <= m; ++i) distColor[i] = INF_INT;\n    queue<int> q;\n    distColor[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (int to = 0; to <= m; ++to) {\n            if (!origAdj[v][to]) continue;\n            if (distColor[to] != INF_INT) continue;\n            distColor[to] = distColor[v] + 1;\n            q.push(to);\n        }\n    }\n\n    for (int i = 0; i <= m; ++i) {\n        int dg = 0;\n        for (int j = 0; j <= m; ++j) if (origAdj[i][j]) ++dg;\n        degColor[i] = dg;\n    }\n\n    int maxDepth = 0;\n    for (int c = 1; c <= m; ++c) maxDepth = max(maxDepth, distColor[c]);\n    depthGroups.assign(maxDepth + 1, {});\n    for (int c = 1; c <= m; ++c) depthGroups[distColor[c]].push_back(c);\n\n    compute_stats(original);\n\n    mt19937 rng((uint32_t)(seed64 ^ (seed64 >> 32)));\n\n    auto start = Clock::now();\n    auto deadline = start + chrono::milliseconds(1930);\n\n    auto sub_deadline = [&](int ms) -> Clock::time_point {\n        return min(deadline, Clock::now() + chrono::milliseconds(ms));\n    };\n\n    Board best = original;\n    Board cur = original;\n\n    // Initial diversified passes.\n    vector<int> initK = {1, 2, 4, 6};\n    for (int k : initK) {\n        if (Clock::now() >= deadline) break;\n        Board cand = shrink_pass(original, rng, sub_deadline(105), k);\n        cand = shave_pass(cand, rng, sub_deadline(120));\n        cand = shrink_pass(cand, rng, sub_deadline(65), k + 1);\n        if (better_board(cand, best)) best = cand;\n    }\n    cur = best;\n\n    int iter = 0;\n    while (Clock::now() < deadline) {\n        Board seed;\n        if (iter % 6 == 0) seed = original;\n        else if (iter % 6 == 1 || iter % 6 == 2) seed = best;\n        else seed = cur;\n\n        Board cand = seed;\n        int k1 = 1 + (rng() % 7);\n        int k2 = 1 + (rng() % 7);\n\n        if (iter % 2 == 0) {\n            cand = shrink_pass(cand, rng, sub_deadline(58), k1);\n            cand = shave_pass(cand, rng, sub_deadline(82));\n            cand = shrink_pass(cand, rng, sub_deadline(48), k2);\n        } else {\n            cand = shave_pass(cand, rng, sub_deadline(70));\n            cand = shrink_pass(cand, rng, sub_deadline(68), k1);\n            cand = shave_pass(cand, rng, sub_deadline(42));\n        }\n\n        if (better_board(cand, best)) best = cand;\n        if (better_board(cand, cur) || iter % 3 == 0) cur = cand;\n        else cur = best;\n\n        ++iter;\n    }\n\n    crop_zero_border(best);\n    compute_stats(best);\n\n    vector<vector<int>> out(n, vector<int>(n, 0));\n    for (int i = 0; i < best.h; ++i) {\n        for (int j = 0; j < best.w; ++j) {\n            out[i][j] = best.a[i * best.w + j];\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << out[i][j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n\n    vector<int> cost_ins;\n    vector<vector<signed char>> itemMemo;\n    vector<vector<signed char>> blockMemo;\n\n    vector<vector<int>> blocks;\n    vector<vector<int>> bins;\n\n    vector<int> order_est;\n    vector<int> rank_pos;\n    vector<double> pweight;\n    vector<double> est_load;\n    vector<double> harm;\n\n    int M = 1;\n    int baseSize = 1;\n    int remBlocks = 0;\n    int iterBound = 0;\n    int reserve_balance = 0;\n    int actual_assigned = 0;\n\n    uint64_t base_seed = 0;\n\n    static signed char enc(char c) {\n        if (c == '>') return 1;\n        if (c == '<') return -1;\n        return 2;\n    }\n    static char dec(signed char v) {\n        if (v == 1) return '>';\n        if (v == -1) return '<';\n        return '=';\n    }\n    static char rev(char c) {\n        if (c == '>') return '<';\n        if (c == '<') return '>';\n        return '=';\n    }\n\n    int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 0, y = 1;\n        while (y < x) y <<= 1, ++p;\n        return p;\n    }\n\n    char ask_sets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) exit(0);\n\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        ++used;\n        return s[0];\n    }\n\n    char cmp_item(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = itemMemo[a][b];\n        if (m != 0) return dec(m);\n        char s = ask_sets(vector<int>{a}, vector<int>{b});\n        itemMemo[a][b] = enc(s);\n        itemMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    char cmp_block(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = blockMemo[a][b];\n        if (m != 0) return dec(m);\n\n        vector<int> L, R;\n        L.reserve(baseSize);\n        R.reserve(baseSize);\n        for (int i = 0; i < baseSize; ++i) L.push_back(blocks[a][i]);\n        for (int i = 0; i < baseSize; ++i) R.push_back(blocks[b][i]);\n\n        char s = ask_sets(L, R);\n        blockMemo[a][b] = enc(s);\n        blockMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    void precompute_costs() {\n        cost_ins.assign(N + 1, 0);\n        for (int n = 1; n <= N; ++n) {\n            cost_ins[n] = cost_ins[n - 1] + ceil_log2_int(n);\n        }\n\n        harm.assign(N + 1, 0.0);\n        for (int i = 1; i <= N; ++i) harm[i] = harm[i - 1] + 1.0 / i;\n    }\n\n    int scheme_cost(int m) {\n        int base = N / m;\n        int rem = N % m;\n        long long c = 1LL * rem * cost_ins[base + 1]\n                    + 1LL * (m - rem) * cost_ins[base]\n                    + cost_ins[m];\n        return (int)c;\n    }\n\n    int estimated_actual_place_count(int extra_queries) {\n        if (D <= 1 || extra_queries <= 0) return 0;\n\n        int simple = extra_queries / max(1, D - 1);\n\n        int h = max(1, ceil_log2_int(D));\n        int tourn = 0;\n        if (extra_queries >= D - 1) {\n            tourn = (extra_queries - (D - 1)) / h;\n        }\n\n        return max(simple, tourn);\n    }\n\n    void choose_scheme() {\n        iterBound = 2 * (D - 1) + 6 + 2 * ceil_log2_int(N);\n        reserve_balance = min(Q, 2 * iterBound);\n\n        double bestScore = -1e100;\n        int bestM = 1;\n\n        for (int m = 1; m <= N; ++m) {\n            int c = scheme_cost(m);\n            if (c > Q) continue;\n            int extra = max(0, Q - c - reserve_balance);\n            double place_cnt = min<double>(N - D, estimated_actual_place_count(extra));\n            double score = m + 1.0 * place_cnt;\n            if (score > bestScore + 1e-12 || (abs(score - bestScore) <= 1e-12 && m > bestM)) {\n                bestScore = score;\n                bestM = m;\n            }\n        }\n\n        M = bestM;\n        baseSize = N / M;\n        remBlocks = N % M;\n    }\n\n    vector<int> sort_items_by_weight(const vector<int>& arr) {\n        vector<int> res;\n        res.reserve(arr.size());\n        for (int x : arr) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_item(x, res[mid]);\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, x);\n        }\n        return res;\n    }\n\n    vector<int> sort_block_ids(const vector<int>& ids) {\n        vector<int> res;\n        res.reserve(ids.size());\n        for (int id : ids) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_block(id, res[mid]);\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, id);\n        }\n        return res;\n    }\n\n    double inv_norm(double p) {\n        p = min(1.0 - 1e-12, max(1e-12, p));\n\n        static const double a1 = -3.969683028665376e+01;\n        static const double a2 =  2.209460984245205e+02;\n        static const double a3 = -2.759285104469687e+02;\n        static const double a4 =  1.383577518672690e+02;\n        static const double a5 = -3.066479806614716e+01;\n        static const double a6 =  2.506628277459239e+00;\n\n        static const double b1 = -5.447609879822406e+01;\n        static const double b2 =  1.615858368580409e+02;\n        static const double b3 = -1.556989798598866e+02;\n        static const double b4 =  6.680131188771972e+01;\n        static const double b5 = -1.328068155288572e+01;\n\n        static const double c1 = -7.784894002430293e-03;\n        static const double c2 = -3.223964580411365e-01;\n        static const double c3 = -2.400758277161838e+00;\n        static const double c4 = -2.549732539343734e+00;\n        static const double c5 =  4.374664141464968e+00;\n        static const double c6 =  2.938163982698783e+00;\n\n        static const double d1 =  7.784695709041462e-03;\n        static const double d2 =  3.224671290700398e-01;\n        static const double d3 =  2.445134137142996e+00;\n        static const double d4 =  3.754408661907416e+00;\n\n        const double plow = 0.02425;\n        const double phigh = 1.0 - plow;\n\n        if (p < plow) {\n            double q = sqrt(-2.0 * log(p));\n            return (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /\n                   ((((d1 * q + d2) * q + d3) * q + d4) * q + 1.0);\n        }\n        if (p > phigh) {\n            double q = sqrt(-2.0 * log(1.0 - p));\n            return -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /\n                    ((((d1 * q + d2) * q + d3) * q + d4) * q + 1.0);\n        }\n        double q = p - 0.5;\n        double r = q * q;\n        return (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q /\n               (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1.0);\n    }\n\n    void build_estimated_order() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n\n        blocks.clear();\n        int cur = 0;\n        for (int i = 0; i < M; ++i) {\n            int sz = baseSize + (i < remBlocks ? 1 : 0);\n            vector<int> blk;\n            blk.reserve(sz);\n            for (int j = 0; j < sz; ++j) blk.push_back(items[cur++]);\n            blocks.push_back(sort_items_by_weight(blk));\n        }\n\n        blockMemo.assign(M, vector<signed char>(M, 0));\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        ids = sort_block_ids(ids);\n\n        struct Cand {\n            double key;\n            int block_rank;\n            int pos_in_block;\n            int item;\n        };\n        vector<Cand> cand;\n        cand.reserve(N);\n\n        double alpha = 0.85;\n        double denom = sqrt((double)max(1, baseSize));\n\n        for (int br = 0; br < M; ++br) {\n            int id = ids[br];\n            int s = (int)blocks[id].size();\n\n            double p = (M - br - 0.5) / (double)M;\n            double z = inv_norm(p);\n            double scale = exp(alpha * z / denom);\n\n            for (int j = 0; j < s; ++j) {\n                int x = blocks[id][j];\n                double inside = harm[s] - harm[j];\n                double key = inside * scale;\n                cand.push_back({key, br, j, x});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [&](const Cand& a, const Cand& b) {\n            if (fabs(a.key - b.key) > 1e-12) return a.key > b.key;\n            if (a.block_rank != b.block_rank) return a.block_rank < b.block_rank;\n            if (a.pos_in_block != b.pos_in_block) return a.pos_in_block < b.pos_in_block;\n            return a.item < b.item;\n        });\n\n        order_est.clear();\n        order_est.reserve(N);\n        rank_pos.assign(N, 0);\n        pweight.assign(N, 0.0);\n\n        for (int i = 0; i < N; ++i) {\n            int x = cand[i].item;\n            order_est.push_back(x);\n            rank_pos[x] = i;\n            pweight[x] = harm[N] - harm[i];\n        }\n    }\n\n    struct MinTournament {\n        Solver* S;\n        int D, SZ;\n        vector<int> tr;\n\n        MinTournament(Solver* solver, int d): S(solver), D(d) {\n            SZ = 1;\n            while (SZ < D) SZ <<= 1;\n            tr.assign(2 * SZ, -1);\n        }\n\n        int better(int a, int b) {\n            if (a == -1) return b;\n            if (b == -1) return a;\n            char s = S->ask_sets(S->bins[a], S->bins[b]);\n            if (s == '<') return a;\n            if (s == '>') return b;\n            return min(a, b);\n        }\n\n        void build() {\n            for (int i = 0; i < D; ++i) tr[SZ + i] = i;\n            for (int i = D; i < SZ; ++i) tr[SZ + i] = -1;\n            for (int i = SZ - 1; i >= 1; --i) tr[i] = better(tr[i << 1], tr[i << 1 | 1]);\n        }\n\n        int winner() const { return tr[1]; }\n\n        void update(int idx) {\n            int p = SZ + idx;\n            tr[p] = idx;\n            p >>= 1;\n            while (p >= 1) {\n                tr[p] = better(tr[p << 1], tr[p << 1 | 1]);\n                p >>= 1;\n            }\n        }\n    };\n\n    int actual_lightest_bin_simple() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            char s = ask_sets(bins[i], bins[best]);\n            if (s == '<') best = i;\n        }\n        return best;\n    }\n\n    int pseudo_lightest_bin_of(const vector<vector<int>>& B, const vector<double>& L) const {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            if (L[i] < L[best] - 1e-12) best = i;\n            else if (fabs(L[i] - L[best]) <= 1e-12) {\n                if (B[i].size() < B[best].size()) best = i;\n                else if (B[i].size() == B[best].size() && i < best) best = i;\n            }\n        }\n        return best;\n    }\n\n    void insert_sorted_bin_to(vector<vector<int>>& B, int b, int item) const {\n        auto &v = B[b];\n        int rk = rank_pos[item];\n        auto it = lower_bound(v.begin(), v.end(), rk,\n                              [&](int lhs_item, int rhs_rank) {\n                                  return rank_pos[lhs_item] < rhs_rank;\n                              });\n        v.insert(it, item);\n    }\n\n    void insert_sorted_bin(int b, int item) {\n        insert_sorted_bin_to(bins, b, item);\n    }\n\n    double objective_of(const vector<double>& L) const {\n        double s = 0.0;\n        for (double x : L) s += x * x;\n        return s;\n    }\n\n    vector<int> sorted_bins_by_load(const vector<vector<int>>& B, const vector<double>& L) const {\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (fabs(L[a] - L[b]) > 1e-12) return L[a] < L[b];\n            if (B[a].size() != B[b].size()) return B[a].size() < B[b].size();\n            return a < b;\n        });\n        return ord;\n    }\n\n    void pseudo_improve_hl_state(vector<vector<int>>& B, vector<double>& L, int max_iter) {\n        for (int iter = 0; iter < max_iter; ++iter) {\n            int h = 0, l = 0;\n            for (int i = 1; i < D; ++i) {\n                if (L[i] > L[h]) h = i;\n                if (L[i] < L[l]) l = i;\n            }\n            if (h == l) break;\n\n            double lh = L[h], ll = L[l];\n            double bestDelta = -1e-12;\n            int bestType = 0;\n            int bestI = -1, bestJ = -1;\n\n            if ((int)B[h].size() > 1) {\n                for (int i = 0; i < (int)B[h].size(); ++i) {\n                    int x = B[h][i];\n                    double w = pweight[x];\n                    double nh = lh - w;\n                    double nl = ll + w;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 1;\n                        bestI = i;\n                    }\n                }\n            }\n\n            for (int i = 0; i < (int)B[h].size(); ++i) {\n                int x = B[h][i];\n                double wx = pweight[x];\n                for (int j = 0; j < (int)B[l].size(); ++j) {\n                    int y = B[l][j];\n                    double wy = pweight[y];\n                    double nh = lh - wx + wy;\n                    double nl = ll - wy + wx;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 2;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestType == 0) break;\n\n            if (bestType == 1) {\n                int x = B[h][bestI];\n                B[h].erase(B[h].begin() + bestI);\n                insert_sorted_bin_to(B, l, x);\n                L[h] -= pweight[x];\n                L[l] += pweight[x];\n            } else {\n                int x = B[h][bestI];\n                int y = B[l][bestJ];\n                B[h].erase(B[h].begin() + bestI);\n                B[l].erase(B[l].begin() + bestJ);\n                insert_sorted_bin_to(B, h, y);\n                insert_sorted_bin_to(B, l, x);\n                L[h] += pweight[y] - pweight[x];\n                L[l] += pweight[x] - pweight[y];\n            }\n        }\n    }\n\n    void pseudo_improve_global_state(vector<vector<int>>& B, vector<double>& L, int max_iter) {\n        auto sq = [&](double x) { return x * x; };\n\n        for (int iter = 0; iter < max_iter; ++iter) {\n            double bestDelta = -1e-12;\n            int bestType = 0;\n            int A = -1, B2 = -1, IA = -1, IB = -1;\n\n            for (int a = 0; a < D; ++a) {\n                if ((int)B[a].size() <= 1) continue;\n                double la = L[a];\n                for (int ia = 0; ia < (int)B[a].size(); ++ia) {\n                    int x = B[a][ia];\n                    double wx = pweight[x];\n                    for (int b = 0; b < D; ++b) if (a != b) {\n                        double lb = L[b];\n                        double delta = sq(la - wx) + sq(lb + wx) - sq(la) - sq(lb);\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestType = 1;\n                            A = a; B2 = b; IA = ia; IB = -1;\n                        }\n                    }\n                }\n            }\n\n            for (int a = 0; a < D; ++a) {\n                double la = L[a];\n                for (int b = a + 1; b < D; ++b) {\n                    double lb = L[b];\n                    for (int ia = 0; ia < (int)B[a].size(); ++ia) {\n                        int x = B[a][ia];\n                        double wx = pweight[x];\n                        for (int ib = 0; ib < (int)B[b].size(); ++ib) {\n                            int y = B[b][ib];\n                            double wy = pweight[y];\n                            double delta = sq(la - wx + wy) + sq(lb - wy + wx) - sq(la) - sq(lb);\n                            if (delta < bestDelta) {\n                                bestDelta = delta;\n                                bestType = 2;\n                                A = a; B2 = b; IA = ia; IB = ib;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (bestType == 0) break;\n\n            if (bestType == 1) {\n                int x = B[A][IA];\n                B[A].erase(B[A].begin() + IA);\n                insert_sorted_bin_to(B, B2, x);\n                L[A] -= pweight[x];\n                L[B2] += pweight[x];\n            } else {\n                int x = B[A][IA];\n                int y = B[B2][IB];\n                B[A].erase(B[A].begin() + IA);\n                B[B2].erase(B[B2].begin() + IB);\n                insert_sorted_bin_to(B, A, y);\n                insert_sorted_bin_to(B, B2, x);\n                L[A] += pweight[y] - pweight[x];\n                L[B2] += pweight[x] - pweight[y];\n            }\n        }\n    }\n\n    void complete_remaining_multistart(const vector<vector<int>>& baseBins,\n                                       const vector<double>& baseLoads,\n                                       const vector<int>& remItems) {\n        if (remItems.empty()) {\n            bins = baseBins;\n            est_load = baseLoads;\n            return;\n        }\n\n        auto do_seq = [&](vector<vector<int>>& B, vector<double>& L) {\n            for (int x : remItems) {\n                int b = pseudo_lightest_bin_of(B, L);\n                B[b].push_back(x);\n                L[b] += pweight[x];\n            }\n        };\n\n        auto do_batchD = [&](vector<vector<int>>& B, vector<double>& L) {\n            int ptr = 0;\n            while (ptr < (int)remItems.size()) {\n                int k = min(D, (int)remItems.size() - ptr);\n                vector<int> ord = sorted_bins_by_load(B, L);\n                for (int j = 0; j < k; ++j) {\n                    int x = remItems[ptr++];\n                    int b = ord[j];\n                    B[b].push_back(x);\n                    L[b] += pweight[x];\n                }\n            }\n        };\n\n        auto do_snake2D = [&](vector<vector<int>>& B, vector<double>& L) {\n            int ptr = 0;\n            while (ptr < (int)remItems.size()) {\n                vector<int> ord = sorted_bins_by_load(B, L);\n                int k1 = min(D, (int)remItems.size() - ptr);\n                for (int j = 0; j < k1; ++j) {\n                    int x = remItems[ptr++];\n                    int b = ord[j];\n                    B[b].push_back(x);\n                    L[b] += pweight[x];\n                }\n                int k2 = min(D, (int)remItems.size() - ptr);\n                for (int j = 0; j < k2; ++j) {\n                    int x = remItems[ptr++];\n                    int b = ord[k2 - 1 - j];\n                    B[b].push_back(x);\n                    L[b] += pweight[x];\n                }\n            }\n        };\n\n        auto do_random_topk = [&](vector<vector<int>>& B, vector<double>& L, int topk, uint64_t seed) {\n            mt19937_64 rng(seed);\n            for (int x : remItems) {\n                vector<int> ord = sorted_bins_by_load(B, L);\n                int k = min(topk, D);\n                int pick = 0;\n                if (k >= 2) {\n                    uniform_int_distribution<int> dist(0, k - 1);\n                    pick = dist(rng);\n                }\n                int b = ord[pick];\n                B[b].push_back(x);\n                L[b] += pweight[x];\n            }\n        };\n\n        auto do_noisy = [&](vector<vector<int>>& B, vector<double>& L, double lambda, uint64_t seed) {\n            mt19937_64 rng(seed);\n            double avgw = 0.0;\n            for (int x : remItems) avgw += pweight[x];\n            avgw /= max<int>(1, remItems.size());\n            uniform_real_distribution<double> dist(0.0, 1.0);\n\n            for (int x : remItems) {\n                int best = 0;\n                double bestScore = 1e100;\n                for (int b = 0; b < D; ++b) {\n                    double score = L[b] + lambda * avgw * dist(rng) + 1e-4 * (double)B[b].size();\n                    if (score < bestScore) {\n                        bestScore = score;\n                        best = b;\n                    }\n                }\n                B[best].push_back(x);\n                L[best] += pweight[x];\n            }\n        };\n\n        double bestObj = 1e300;\n        vector<vector<int>> bestBins;\n        vector<double> bestLoads;\n\n        int mild_hl = 250;\n        int mild_gl = 25;\n\n        int methods = 6;\n        for (int method = 0; method < methods; ++method) {\n            vector<vector<int>> B = baseBins;\n            vector<double> L = baseLoads;\n\n            if (method == 0) {\n                do_seq(B, L);\n            } else if (method == 1) {\n                do_batchD(B, L);\n            } else if (method == 2) {\n                do_snake2D(B, L);\n            } else if (method == 3) {\n                do_random_topk(B, L, 2, base_seed + 1001);\n            } else if (method == 4) {\n                do_random_topk(B, L, min(3, D), base_seed + 2003);\n            } else if (method == 5) {\n                do_noisy(B, L, 0.08, base_seed + 3007);\n            }\n\n            pseudo_improve_hl_state(B, L, mild_hl);\n            pseudo_improve_global_state(B, L, mild_gl);\n\n            double obj = objective_of(L);\n            double mx = *max_element(L.begin(), L.end());\n            double mn = *min_element(L.begin(), L.end());\n            obj += 1e-9 * (mx - mn);\n\n            if (obj < bestObj) {\n                bestObj = obj;\n                bestBins.swap(B);\n                bestLoads.swap(L);\n            }\n        }\n\n        bins.swap(bestBins);\n        est_load.swap(bestLoads);\n    }\n\n    void assign_initial() {\n        bins.assign(D, {});\n        est_load.assign(D, 0.0);\n        actual_assigned = 0;\n\n        int ptr = 0;\n        for (int b = 0; b < D; ++b) {\n            int x = order_est[ptr++];\n            bins[b].push_back(x);\n            est_load[b] += pweight[x];\n        }\n\n        int rem = max(0, Q - used - reserve_balance);\n        int simpleK = rem / max(1, D - 1);\n\n        int h = max(1, ceil_log2_int(D));\n        int tournK = 0;\n        if (rem >= D - 1) {\n            tournK = (rem - (D - 1)) / h;\n        }\n\n        int remaining_items = N - ptr;\n        bool use_tournament = false;\n        int K = 0;\n\n        if (tournK > simpleK && tournK >= 2) {\n            use_tournament = true;\n            K = min(remaining_items, tournK);\n        } else {\n            K = min(remaining_items, simpleK);\n        }\n\n        if (use_tournament && K > 0) {\n            MinTournament tour(this, D);\n            tour.build();\n            for (int t = 0; t < K; ++t) {\n                int x = order_est[ptr++];\n                int b = tour.winner();\n                bins[b].push_back(x);\n                est_load[b] += pweight[x];\n                tour.update(b);\n                ++actual_assigned;\n            }\n        } else {\n            for (int t = 0; t < K; ++t) {\n                int x = order_est[ptr++];\n                int b = actual_lightest_bin_simple();\n                bins[b].push_back(x);\n                est_load[b] += pweight[x];\n                ++actual_assigned;\n            }\n        }\n\n        vector<vector<int>> baseBins = bins;\n        vector<double> baseLoads = est_load;\n        vector<int> remItems;\n        remItems.reserve(N - ptr);\n        while (ptr < N) remItems.push_back(order_est[ptr++]);\n\n        complete_remaining_multistart(baseBins, baseLoads, remItems);\n    }\n\n    void pseudo_improve_hl(int max_iter) {\n        pseudo_improve_hl_state(bins, est_load, max_iter);\n    }\n\n    void pseudo_improve_global(int max_iter) {\n        pseudo_improve_global_state(bins, est_load, max_iter);\n    }\n\n    pair<int, int> actual_extremes() {\n        vector<vector<signed char>> memo(D, vector<signed char>(D, 0));\n        auto cmpBin = [&](int a, int b) -> char {\n            if (a == b) return '=';\n            signed char &m = memo[a][b];\n            if (m != 0) return dec(m);\n            char s = ask_sets(bins[a], bins[b]);\n            memo[a][b] = enc(s);\n            memo[b][a] = enc(rev(s));\n            return s;\n        };\n\n        int hi = 0, lo = 0;\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, hi) == '>') hi = i;\n        }\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, lo) == '<') lo = i;\n        }\n        return {hi, lo};\n    }\n\n    int select_move_candidate(int H, int L) {\n        int m = (int)bins[H].size();\n        if (m <= 1) return -1;\n\n        vector<signed char> memo(m, 0);\n        auto test = [&](int idx) -> char {\n            if (memo[idx] != 0) return dec(memo[idx]);\n            vector<int> left, right;\n            left.reserve(m - 1);\n            right.reserve(bins[L].size() + 1);\n            for (int i = 0; i < m; ++i) if (i != idx) left.push_back(bins[H][i]);\n            for (int x : bins[L]) right.push_back(x);\n            right.push_back(bins[H][idx]);\n            char s = ask_sets(left, right);\n            memo[idx] = enc(s);\n            return s;\n        };\n\n        char s0 = test(0);\n        if (s0 == '>' || s0 == '=') return 0;\n\n        char sl = test(m - 1);\n        if (sl == '=') return m - 1;\n        if (sl == '<') return -1;\n\n        int lo = 0, hi = m - 1;\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '<') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double v1 = fabs(diff - 2.0 * pweight[bins[H][lo]]);\n        double v2 = fabs(diff - 2.0 * pweight[bins[H][hi]]);\n        return (v2 < v1 ? hi : lo);\n    }\n\n    int select_swap_candidate(int H, int L) {\n        int xidx = (int)bins[H].size() - 1;\n        int x = bins[H][xidx];\n        int rkx = rank_pos[x];\n\n        int n = (int)bins[L].size();\n        int first = 0;\n        while (first < n && rank_pos[bins[L][first]] < rkx) ++first;\n        if (first == n) return -1;\n\n        vector<signed char> memo(n, 0);\n        auto test = [&](int yidx) -> char {\n            if (memo[yidx] != 0) return dec(memo[yidx]);\n            vector<int> left, right;\n            left.reserve(bins[H].size());\n            right.reserve(bins[L].size());\n            for (int i = 0; i < (int)bins[H].size(); ++i) {\n                if (i != xidx) left.push_back(bins[H][i]);\n            }\n            left.push_back(bins[L][yidx]);\n\n            for (int i = 0; i < (int)bins[L].size(); ++i) {\n                if (i != yidx) right.push_back(bins[L][i]);\n            }\n            right.push_back(x);\n\n            char s = ask_sets(left, right);\n            memo[yidx] = enc(s);\n            return s;\n        };\n\n        char sf = test(first);\n        if (sf == '=') return first;\n        if (sf == '<') return -1;\n\n        char sl = test(n - 1);\n        if (sl == '=') return n - 1;\n        if (sl == '>') return n - 1;\n\n        int lo = first, hi = n - 1;\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '>') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double wx = pweight[x];\n        double d1 = fabs(diff - 2.0 * (wx - pweight[bins[L][lo]]));\n        double d2 = fabs(diff - 2.0 * (wx - pweight[bins[L][hi]]));\n        return (d2 < d1 ? hi : lo);\n    }\n\n    void apply_move(int H, int L, int idx) {\n        int x = bins[H][idx];\n        bins[H].erase(bins[H].begin() + idx);\n        insert_sorted_bin(L, x);\n        est_load[H] -= pweight[x];\n        est_load[L] += pweight[x];\n    }\n\n    void apply_swap(int H, int L, int yidx) {\n        int xidx = (int)bins[H].size() - 1;\n        int x = bins[H][xidx];\n        int y = bins[L][yidx];\n\n        bins[H].erase(bins[H].begin() + xidx);\n        bins[L].erase(bins[L].begin() + yidx);\n        insert_sorted_bin(H, y);\n        insert_sorted_bin(L, x);\n\n        est_load[H] += pweight[y] - pweight[x];\n        est_load[L] += pweight[x] - pweight[y];\n    }\n\n    void actual_improve() {\n        while (used + iterBound <= Q) {\n            auto [H, L] = actual_extremes();\n            if (H == L) break;\n\n            bool changed = false;\n\n            if ((int)bins[H].size() > 1) {\n                int idx = select_move_candidate(H, L);\n                if (idx != -1) {\n                    apply_move(H, L, idx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) {\n                int yidx = select_swap_candidate(H, L);\n                if (yidx != -1) {\n                    apply_swap(H, L, yidx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void fill_dummy_queries() {\n        while (used < Q) {\n            ask_sets(vector<int>{0}, vector<int>{1});\n        }\n    }\n\n    void output_answer() {\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b]) ans[x] = b;\n        }\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n        base_seed = 1469598103934665603ULL;\n        base_seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL + (base_seed << 6) + (base_seed >> 2);\n        base_seed ^= (uint64_t)D + 0x9e3779b97f4a7c15ULL + (base_seed << 6) + (base_seed >> 2);\n        base_seed ^= (uint64_t)Q + 0x9e3779b97f4a7c15ULL + (base_seed << 6) + (base_seed >> 2);\n\n        itemMemo.assign(N, vector<signed char>(N, 0));\n\n        precompute_costs();\n        choose_scheme();\n        build_estimated_order();\n        assign_initial();\n\n        int hl_iters = 1500;\n        int global_iters = 120;\n        int rem_items = max(1, N - D);\n\n        if (actual_assigned * 4 >= 3 * rem_items) {\n            hl_iters = 350;\n            global_iters = 50;\n        } else if (actual_assigned * 2 >= rem_items) {\n            hl_iters = 800;\n            global_iters = 80;\n        }\n\n        pseudo_improve_hl(hl_iters);\n        pseudo_improve_global(global_iters);\n        actual_improve();\n        fill_dummy_queries();\n        output_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NMAX = 200;\nstatic constexpr int MMAX = 10;\nstatic constexpr uint8_t REMOVED = 255;\nstatic constexpr int INF = 1e9;\n\nint N, M;\nchrono::steady_clock::time_point g_start;\ndouble g_deadline = 1.80;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nstruct State {\n    uint8_t a[MMAX][NMAX];   // bottom -> top\n    uint8_t h[MMAX];\n    uint8_t st_of[NMAX + 1]; // stack id, or 255 if removed\n    uint8_t pos[NMAX + 1];   // position in stack\n    uint16_t cur;            // next box to remove\n};\n\nstruct Result {\n    int energy = INF;\n    vector<pair<int,int>> ops;\n};\n\nstruct Features {\n    int solo = 0;     // optimistic cost if blockers moved out disappear forever\n    int bad = 0;      // non-record-minima from bottom\n    int seg = 0;      // forced future expensive moves in solo model\n    int empty = 0;\n};\n\nstruct Node {\n    State st;\n    int g;            // exact energy so far\n    int parent;       // index in nodes, -1 for root\n    uint8_t actionTo; // 1..M, 0 for root\n};\n\nstruct TempChild {\n    State st;\n    int g;\n    int hval;\n    int eval;\n    int parent;\n    uint8_t actionTo;\n    uint16_t cur;\n};\n\nstruct Config {\n    int width;\n    int mode;\n    int greedyDepth;\n};\n\ninline void pop_all(State& st, vector<pair<int,int>>* ops = nullptr) {\n    while (st.cur <= N) {\n        uint8_t s = st.st_of[st.cur];\n        if (s == REMOVED) {\n            ++st.cur;\n            continue;\n        }\n        if ((int)st.pos[st.cur] + 1 != (int)st.h[s]) break;\n        if (ops) ops->push_back({(int)st.cur, 0});\n        --st.h[s];\n        st.st_of[st.cur] = REMOVED;\n        ++st.cur;\n    }\n}\n\ninline int move_blockers(State& st, int dst) {\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    int start = p + 1;\n    int len = (int)st.h[s] - start;\n    for (int i = start; i < (int)st.h[s]; ++i) {\n        uint8_t x = st.a[s][i];\n        st.a[dst][st.h[dst]] = x;\n        st.st_of[x] = (uint8_t)dst;\n        st.pos[x] = st.h[dst];\n        ++st.h[dst];\n    }\n    st.h[s] = (uint8_t)start;\n    return len;\n}\n\ninline Features calc_features(const State& st) {\n    Features f;\n    int recPos[NMAX];\n\n    for (int i = 0; i < M; ++i) {\n        int h = st.h[i];\n        if (h == 0) {\n            ++f.empty;\n            continue;\n        }\n\n        int rc = 0;\n        int mn = N + 1;\n        for (int j = 0; j < h; ++j) {\n            int x = st.a[i][j];\n            if (x < mn) {\n                mn = x;\n                recPos[rc++] = j;\n            }\n        }\n\n        f.bad += h - rc;\n\n        for (int k = rc - 1; k >= 0; --k) {\n            int end = (k + 1 < rc ? recPos[k + 1] - 1 : h - 1);\n            int above = end - recPos[k];\n            if (above > 0) {\n                f.solo += above + 1;\n                ++f.seg;\n            }\n        }\n    }\n    return f;\n}\n\ninline int estimate(const State& st, int mode) {\n    Features f = calc_features(st);\n    switch (mode) {\n        case 0: return f.solo;\n        case 1: return f.solo + f.bad;\n        case 2: return f.solo + 2 * f.bad;\n        case 3: return f.solo + f.bad + f.seg;\n        default: return f.solo;\n    }\n}\n\nint lookahead_cost(const State& st, int depth, int mode) {\n    if (st.cur > N) return 0;\n    if (elapsed_sec() > g_deadline) return estimate(st, mode);\n\n    if (depth == 0) return estimate(st, mode);\n\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    if (p + 1 >= (int)st.h[s]) {\n        State nx = st;\n        pop_all(nx, nullptr);\n        return lookahead_cost(nx, depth, mode);\n    }\n\n    int len = (int)st.h[s] - p - 1;\n    int best = INF;\n\n    struct Cand {\n        int dst;\n        int hval;\n        int nextCur;\n        State st;\n    };\n    Cand cand[MMAX - 1];\n    int cnt = 0;\n\n    for (int dst = 0; dst < M; ++dst) {\n        if (dst == s) continue;\n        cand[cnt].dst = dst;\n        cand[cnt].st = st;\n        move_blockers(cand[cnt].st, dst);\n        pop_all(cand[cnt].st, nullptr);\n        cand[cnt].hval = estimate(cand[cnt].st, mode);\n        cand[cnt].nextCur = cand[cnt].st.cur;\n        ++cnt;\n    }\n\n    array<int, MMAX - 1> ord{};\n    iota(ord.begin(), ord.begin() + cnt, 0);\n    sort(ord.begin(), ord.begin() + cnt, [&](int i, int j) {\n        if (cand[i].hval != cand[j].hval) return cand[i].hval < cand[j].hval;\n        if (cand[i].nextCur != cand[j].nextCur) return cand[i].nextCur > cand[j].nextCur;\n        return cand[i].dst < cand[j].dst;\n    });\n\n    int limit = cnt;\n    if (depth >= 2) limit = min(limit, 5);\n\n    for (int k = 0; k < limit; ++k) {\n        const auto& c = cand[ord[k]];\n        best = min(best, len + 1 + lookahead_cost(c.st, depth - 1, mode));\n    }\n    return best;\n}\n\nResult greedy_complete(State st, int mode, int depth) {\n    Result res;\n    res.energy = 0;\n    pop_all(st, &res.ops);\n\n    while (st.cur <= N) {\n        int cur = st.cur;\n        int s = st.st_of[cur];\n        int p = st.pos[cur];\n\n        if (p + 1 >= (int)st.h[s]) {\n            pop_all(st, &res.ops);\n            continue;\n        }\n\n        int len = (int)st.h[s] - p - 1;\n        int v = st.a[s][p + 1];\n\n        int useDepth = depth;\n        if (elapsed_sec() > g_deadline - 0.03) useDepth = 1;\n\n        int bestDst = -1;\n        int bestVal = INF;\n        int bestCur = -1;\n        int bestH = INF;\n\n        for (int dst = 0; dst < M; ++dst) {\n            if (dst == s) continue;\n            State nx = st;\n            move_blockers(nx, dst);\n            pop_all(nx, nullptr);\n            int hval = estimate(nx, mode);\n            int val = len + 1 + (useDepth > 1 ? lookahead_cost(nx, useDepth - 1, mode) : hval);\n\n            if (val < bestVal ||\n                (val == bestVal && nx.cur > bestCur) ||\n                (val == bestVal && nx.cur == bestCur && hval < bestH) ||\n                (val == bestVal && nx.cur == bestCur && hval == bestH && dst < bestDst)) {\n                bestVal = val;\n                bestDst = dst;\n                bestCur = nx.cur;\n                bestH = hval;\n            }\n        }\n\n        res.ops.push_back({v, bestDst + 1});\n        res.energy += len + 1;\n        move_blockers(st, bestDst);\n        pop_all(st, &res.ops);\n    }\n\n    return res;\n}\n\nvector<uint8_t> collect_destinations(const vector<Node>& nodes, int idx) {\n    vector<uint8_t> rev;\n    while (idx != -1 && nodes[idx].parent != -1) {\n        rev.push_back(nodes[idx].actionTo);\n        idx = nodes[idx].parent;\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nstruct ReplayResult {\n    State st;\n    int energy = 0;\n    vector<pair<int,int>> ops;\n};\n\nReplayResult replay_destinations(const State& rawInit, const vector<uint8_t>& dests) {\n    ReplayResult rr;\n    rr.st = rawInit;\n    rr.energy = 0;\n    rr.ops.clear();\n\n    pop_all(rr.st, &rr.ops);\n\n    for (uint8_t to : dests) {\n        if (rr.st.cur > N) break;\n\n        int cur = rr.st.cur;\n        int s = rr.st.st_of[cur];\n        int p = rr.st.pos[cur];\n\n        if (p + 1 >= (int)rr.st.h[s]) {\n            pop_all(rr.st, &rr.ops);\n            continue;\n        }\n\n        int v = rr.st.a[s][p + 1];\n        int len = (int)rr.st.h[s] - p - 1;\n\n        rr.ops.push_back({v, (int)to});\n        rr.energy += len + 1;\n        move_blockers(rr.st, (int)to - 1);\n        pop_all(rr.st, &rr.ops);\n    }\n    return rr;\n}\n\nbool validate_result(const State& rawInit, const Result& res) {\n    State st = rawInit;\n    int energy = 0;\n\n    for (auto [v, to] : res.ops) {\n        if (to == 0) {\n            if (st.cur != v) return false;\n            if (v < 1 || v > N) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            if ((int)st.pos[v] + 1 != (int)st.h[s]) return false;\n            --st.h[s];\n            st.st_of[v] = REMOVED;\n            ++st.cur;\n        } else {\n            if (v < 1 || v > N || to < 1 || to > M) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            int p = st.pos[v];\n            int dst = to - 1;\n            int len = (int)st.h[s] - p;\n            for (int i = p; i < (int)st.h[s]; ++i) {\n                uint8_t x = st.a[s][i];\n                st.a[dst][st.h[dst]] = x;\n                st.st_of[x] = (uint8_t)dst;\n                st.pos[x] = st.h[dst];\n                ++st.h[dst];\n            }\n            st.h[s] = (uint8_t)p;\n            energy += len + 1;\n        }\n    }\n    return st.cur == N + 1 && energy == res.energy && (int)res.ops.size() <= 5000;\n}\n\nResult run_beam(const State& rawInit, const Config& cfg, double deadline) {\n    State start = rawInit;\n    pop_all(start, nullptr);\n\n    vector<Node> nodes;\n    nodes.reserve(cfg.width * 260 + 10);\n    nodes.push_back(Node{start, 0, -1, 0});\n\n    if (start.cur > N) {\n        ReplayResult rr = replay_destinations(rawInit, {});\n        return Result{rr.energy, rr.ops};\n    }\n\n    vector<int> beam = {0};\n    int bestFinishedIdx = -1;\n    int bestFinishedCost = INF;\n\n    while (!beam.empty()) {\n        if (elapsed_sec() > deadline) break;\n\n        vector<TempChild> cand;\n        cand.reserve((int)beam.size() * (M - 1));\n\n        bool hasBestTemp = false;\n        TempChild bestTemp{};\n\n        for (int idx : beam) {\n            const Node& nd = nodes[idx];\n            const State& st = nd.st;\n\n            if (st.cur > N) {\n                if (nd.g < bestFinishedCost) {\n                    bestFinishedCost = nd.g;\n                    bestFinishedIdx = idx;\n                }\n                continue;\n            }\n\n            int cur = st.cur;\n            int s = st.st_of[cur];\n            int p = st.pos[cur];\n\n            if (p + 1 >= (int)st.h[s]) continue;\n\n            int len = (int)st.h[s] - p - 1;\n\n            for (int dst = 0; dst < M; ++dst) {\n                if (dst == s) continue;\n\n                TempChild tc;\n                tc.st = st;\n                move_blockers(tc.st, dst);\n                pop_all(tc.st, nullptr);\n                tc.g = nd.g + len + 1;\n                tc.hval = estimate(tc.st, cfg.mode);\n                tc.eval = tc.g + tc.hval;\n                tc.parent = idx;\n                tc.actionTo = (uint8_t)(dst + 1);\n                tc.cur = tc.st.cur;\n\n                if (tc.st.cur > N) {\n                    if (tc.g < bestFinishedCost &&\n                        (!hasBestTemp || tc.g < bestTemp.g)) {\n                        hasBestTemp = true;\n                        bestTemp = tc;\n                    }\n                } else {\n                    cand.push_back(std::move(tc));\n                }\n            }\n        }\n\n        if (hasBestTemp) {\n            nodes.push_back(Node{bestTemp.st, bestTemp.g, bestTemp.parent, bestTemp.actionTo});\n            bestFinishedIdx = (int)nodes.size() - 1;\n            bestFinishedCost = bestTemp.g;\n        }\n\n        if (cand.empty()) break;\n\n        vector<int> ord(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n        auto cmp = [&](int i, int j) {\n            const auto& A = cand[i];\n            const auto& B = cand[j];\n            if (A.eval != B.eval) return A.eval < B.eval;\n            if (A.hval != B.hval) return A.hval < B.hval;\n            if (A.cur != B.cur) return A.cur > B.cur;\n            if (A.g != B.g) return A.g < B.g;\n            return A.actionTo < B.actionTo;\n        };\n\n        if ((int)ord.size() > cfg.width) {\n            nth_element(ord.begin(), ord.begin() + cfg.width, ord.end(), cmp);\n            ord.resize(cfg.width);\n        }\n        sort(ord.begin(), ord.end(), cmp);\n\n        vector<int> nextBeam;\n        nextBeam.reserve(ord.size());\n        for (int id : ord) {\n            const auto& tc = cand[id];\n            nodes.push_back(Node{tc.st, tc.g, tc.parent, tc.actionTo});\n            nextBeam.push_back((int)nodes.size() - 1);\n        }\n        beam.swap(nextBeam);\n    }\n\n    Result best;\n    best.energy = INF;\n\n    if (bestFinishedIdx != -1) {\n        auto dests = collect_destinations(nodes, bestFinishedIdx);\n        ReplayResult rr = replay_destinations(rawInit, dests);\n        if (rr.st.cur == N + 1) {\n            best.energy = rr.energy;\n            best.ops = std::move(rr.ops);\n        }\n    }\n\n    for (int t = 0; t < (int)beam.size() && t < 3 && elapsed_sec() <= deadline + 0.01; ++t) {\n        int idx = beam[t];\n        auto dests = collect_destinations(nodes, idx);\n        ReplayResult pref = replay_destinations(rawInit, dests);\n        Result tail = greedy_complete(pref.st, cfg.mode, cfg.greedyDepth);\n\n        Result candRes;\n        candRes.energy = pref.energy + tail.energy;\n        candRes.ops = std::move(pref.ops);\n        candRes.ops.insert(candRes.ops.end(), tail.ops.begin(), tail.ops.end());\n\n        if (candRes.energy < best.energy ||\n            (candRes.energy == best.energy && candRes.ops.size() < best.ops.size())) {\n            best = std::move(candRes);\n        }\n    }\n\n    if (best.energy == INF) {\n        ReplayResult pref = replay_destinations(rawInit, {});\n        Result tail = greedy_complete(pref.st, cfg.mode, max(1, cfg.greedyDepth));\n        best.energy = pref.energy + tail.energy;\n        best.ops = std::move(pref.ops);\n        best.ops.insert(best.ops.end(), tail.ops.begin(), tail.ops.end());\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> N >> M;\n\n    State rawInit{};\n    rawInit.cur = 1;\n    for (int i = 0; i < M; ++i) {\n        rawInit.h[i] = N / M;\n        for (int j = 0; j < N / M; ++j) {\n            int x;\n            cin >> x;\n            rawInit.a[i][j] = (uint8_t)x;\n            rawInit.st_of[x] = (uint8_t)i;\n            rawInit.pos[x] = (uint8_t)j;\n        }\n    }\n\n    const double deadline = g_deadline;\n\n    Result best;\n    best.energy = INF;\n\n    auto try_update = [&](Result&& cand) {\n        if (!validate_result(rawInit, cand)) return;\n        if (cand.energy < best.energy ||\n            (cand.energy == best.energy && cand.ops.size() < best.ops.size())) {\n            best = std::move(cand);\n        }\n    };\n\n    // Strong accepted-style beam portfolio\n    vector<Config> beamConfigs = {\n        {180, 0, 2},\n        {120, 1, 2},\n        {80,  3, 1},\n        {60,  2, 2},\n    };\n\n    for (const auto& cfg : beamConfigs) {\n        if (elapsed_sec() > deadline) break;\n        try_update(run_beam(rawInit, cfg, deadline));\n    }\n\n    // Cheap diversified pure greedy runs\n    if (elapsed_sec() < deadline) try_update(greedy_complete(rawInit, 0, 2));\n    if (elapsed_sec() < deadline) try_update(greedy_complete(rawInit, 1, 2));\n    if (elapsed_sec() < deadline) try_update(greedy_complete(rawInit, 2, 2));\n    if (elapsed_sec() < deadline) try_update(greedy_complete(rawInit, 3, 1));\n\n    // Absolute safe fallback\n    if (best.energy == INF) {\n        Result cur = greedy_complete(rawInit, 0, 2);\n        if (!validate_result(rawInit, cur)) {\n            cur = greedy_complete(rawInit, 1, 1);\n        }\n        best = std::move(cur);\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF64 = (1LL << 62);\nstatic constexpr int MAXV = 1600;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = chrono::steady_clock::now().time_since_epoch().count()) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next() % (uint64_t)n); }\n};\n\nstruct Score {\n    long long num;\n    int L;\n};\n\nstatic inline bool better_score(const Score& a, const Score& b) {\n    __int128 lhs = (__int128)a.num * b.L;\n    __int128 rhs = (__int128)b.num * a.L;\n    if (lhs != rhs) return lhs < rhs;\n    return a.L < b.L;\n}\n\nstruct State {\n    vector<int> parent;\n    vector<int> sz, depth, tin, tout;\n    vector<long long> subD;\n    long long num = INF64;\n};\n\nstruct Comp {\n    string route;\n    vector<int> pos; // pos[0]=0\n    int len = 0;\n    Score score{INF64, 1};\n};\n\nint N, Vn, TREE_LEN;\nvector<int> g[MAXV];\nint dirtv[MAXV];\nlong long sqrtv_[MAXV];\nlong long imp1[MAXV], imp2[MAXV], imp3[MAXV], imp4[MAXV];\nint distRoot[MAXV], bfsParent[MAXV];\n\nint firstOcc[MAXV], lastOcc[MAXV];\nlong long gapAcc[MAXV];\n\nXorShift64 rng;\nchrono::steady_clock::time_point global_start_time;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - global_start_time).count();\n}\n\ninline int vid(int r, int c) { return r * N + c; }\n\ninline char move_char(int a, int b) {\n    if (b == a + 1) return 'R';\n    if (b == a - 1) return 'L';\n    if (b == a + N) return 'D';\n    return 'U';\n}\n\ninline long long tri(long long x) {\n    return x * (x - 1) / 2;\n}\n\n// Exact contribution used in rooted-tree Euler tour objective\ninline long long node_term(int x, int szx, int parentD) {\n    long long outside_gap = TREE_LEN - 2LL * (szx - 1);\n    long long child_gap = 2LL * szx;\n    return 1LL * dirtv[x] * tri(outside_gap) + 1LL * parentD * tri(child_gap);\n}\n\nuint64_t hash_route(const string& s) {\n    uint64_t h = 1469598103934665603ULL;\n    for (unsigned char c : s) {\n        h ^= (uint64_t)c;\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)s.size() + 0x9e3779b97f4a7c15ULL;\n    h *= 1099511628211ULL;\n    return h;\n}\n\nvoid compute_root_bfs() {\n    fill(distRoot, distRoot + Vn, -1);\n    fill(bfsParent, bfsParent + Vn, -1);\n    queue<int> q;\n    distRoot[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int u = q.front();\n        q.pop();\n        for (int to : g[u]) {\n            if (distRoot[to] == -1) {\n                distRoot[to] = distRoot[u] + 1;\n                bfsParent[to] = u;\n                q.push(to);\n            }\n        }\n    }\n}\n\nState build_state(const vector<int>& parent) {\n    State st;\n    st.parent = parent;\n    st.sz.assign(Vn, 1);\n    st.depth.assign(Vn, 0);\n    st.tin.assign(Vn, 0);\n    st.tout.assign(Vn, 0);\n    st.subD.assign(Vn, 0);\n\n    static vector<int> ch[MAXV];\n    for (int i = 0; i < Vn; i++) ch[i].clear();\n    for (int v = 1; v < Vn; v++) ch[parent[v]].push_back(v);\n\n    vector<int> post;\n    post.reserve(Vn);\n    int timer = 0;\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        st.tin[u] = timer++;\n        for (int c : ch[u]) {\n            st.depth[c] = st.depth[u] + 1;\n            self(self, c);\n        }\n        st.tout[u] = timer;\n        post.push_back(u);\n    };\n    dfs(dfs, 0);\n\n    for (int u : post) {\n        st.sz[u] = 1;\n        st.subD[u] = dirtv[u];\n        for (int c : ch[u]) {\n            st.sz[u] += st.sz[c];\n            st.subD[u] += st.subD[c];\n        }\n    }\n\n    long long num = 0;\n    for (int x = 1; x < Vn; x++) {\n        num += node_term(x, st.sz[x], dirtv[st.parent[x]]);\n    }\n    st.num = num;\n    return st;\n}\n\ninline bool is_descendant(const State& st, int x, int anc) {\n    return st.tin[anc] <= st.tin[x] && st.tout[x] <= st.tout[anc];\n}\n\nint lca_slow(const State& st, int a, int b) {\n    while (st.depth[a] > st.depth[b]) a = st.parent[a];\n    while (st.depth[b] > st.depth[a]) b = st.parent[b];\n    while (a != b) {\n        a = st.parent[a];\n        b = st.parent[b];\n    }\n    return a;\n}\n\nlong long delta_reparent(const State& st, int u, int w) {\n    int p = st.parent[u];\n    int s = st.sz[u];\n    int l = lca_slow(st, p, w);\n\n    long long delta = 0;\n\n    delta += node_term(u, s, dirtv[w]) - node_term(u, s, dirtv[p]);\n\n    for (int x = p; x != l; x = st.parent[x]) {\n        delta += node_term(x, st.sz[x] - s, dirtv[st.parent[x]])\n               - node_term(x, st.sz[x],     dirtv[st.parent[x]]);\n    }\n    for (int x = w; x != l; x = st.parent[x]) {\n        delta += node_term(x, st.sz[x] + s, dirtv[st.parent[x]])\n               - node_term(x, st.sz[x],     dirtv[st.parent[x]]);\n    }\n\n    return delta;\n}\n\nlong long rand_noise(long long amp) {\n    if (amp == 0) return 0;\n    return (long long)(rng.next() % (uint64_t)(2 * amp + 1)) - amp;\n}\n\nvector<int> gen_spt(const long long* imp) {\n    vector<int> parent(Vn, -1);\n    for (int u = 1; u < Vn; u++) {\n        int best = -1;\n        for (int p : g[u]) {\n            if (distRoot[p] == distRoot[u] - 1) {\n                if (best == -1 || imp[p] > imp[best] || (imp[p] == imp[best] && p < best)) best = p;\n            }\n        }\n        parent[u] = best;\n    }\n    return parent;\n}\n\nvector<int> gen_weighted_dfs(const long long* imp, long long noise) {\n    vector<int> parent(Vn, -1);\n    vector<char> vis(Vn, 0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        vis[u] = 1;\n        vector<pair<long long, int>> cand;\n        cand.reserve(g[u].size());\n        for (int to : g[u]) cand.push_back({imp[to] + rand_noise(noise), to});\n        sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        for (auto& e : cand) {\n            int to = e.second;\n            if (!vis[to]) {\n                parent[to] = u;\n                self(self, to);\n            }\n        }\n    };\n    dfs(dfs, 0);\n    return parent;\n}\n\nvector<int> gen_prim(const long long* imp, long long noise, int depthPenalty) {\n    struct Node {\n        long long key;\n        uint64_t tie;\n        int from, to;\n        bool operator<(const Node& other) const {\n            if (key != other.key) return key < other.key;\n            return tie < other.tie;\n        }\n    };\n\n    vector<int> parent(Vn, -1), depth(Vn, 0);\n    vector<char> used(Vn, 0);\n    priority_queue<Node> pq;\n\n    auto push_edges = [&](int u) {\n        for (int to : g[u]) if (!used[to]) {\n            long long key = imp[to] - 1LL * depthPenalty * depth[u] + rand_noise(noise);\n            pq.push({key, rng.next(), u, to});\n        }\n    };\n\n    used[0] = 1;\n    int cnt = 1;\n    push_edges(0);\n\n    while (!pq.empty() && cnt < Vn) {\n        auto cur = pq.top();\n        pq.pop();\n        if (used[cur.to]) continue;\n        used[cur.to] = 1;\n        parent[cur.to] = cur.from;\n        depth[cur.to] = depth[cur.from] + 1;\n        cnt++;\n        push_edges(cur.to);\n    }\n\n    if (cnt < Vn) return gen_weighted_dfs(imp, 0);\n    return parent;\n}\n\nvector<int> make_static_hot_list() {\n    vector<pair<long long, int>> cand;\n    cand.reserve(4 * Vn);\n    for (int u = 1; u < Vn; u++) {\n        cand.push_back({1LL * dirtv[u] * 1000000LL, u});\n        cand.push_back({sqrtv_[u] * 1000000LL, u});\n        cand.push_back({1LL * dirtv[u] * 1000000LL / (distRoot[u] + 1), u});\n        cand.push_back({sqrtv_[u] * 1000000LL / (distRoot[u] + 1), u});\n    }\n    sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n        if (A.first != B.first) return A.first > B.first;\n        return A.second < B.second;\n    });\n    vector<int> res;\n    vector<char> used(Vn, 0);\n    for (auto& e : cand) {\n        int u = e.second;\n        if (!used[u]) {\n            used[u] = 1;\n            res.push_back(u);\n            if ((int)res.size() >= 200) break;\n        }\n    }\n    return res;\n}\n\nvector<int> make_top_bad(const State& st, int limit = 120) {\n    vector<pair<long long, int>> vec;\n    vec.reserve(Vn - 1);\n    for (int x = 1; x < Vn; x++) {\n        vec.push_back({node_term(x, st.sz[x], dirtv[st.parent[x]]), x});\n    }\n    sort(vec.begin(), vec.end(), [&](auto& A, auto& B) {\n        if (A.first != B.first) return A.first > B.first;\n        return A.second < B.second;\n    });\n    vector<int> res;\n    for (int i = 0; i < (int)vec.size() && i < limit; i++) res.push_back(vec[i].second);\n    return res;\n}\n\nvoid consider_pool(vector<State>& pool, const State& st, int maxPool = 6) {\n    if ((int)pool.size() >= maxPool && st.num >= pool.back().num) return;\n    pool.push_back(st);\n    sort(pool.begin(), pool.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n    if ((int)pool.size() > maxPool) pool.pop_back();\n}\n\nvoid build_children_sorted(const State& st, vector<vector<int>>& ch, int mode) {\n    ch.assign(Vn, {});\n    for (int v = 1; v < Vn; v++) ch[st.parent[v]].push_back(v);\n\n    for (int u = 0; u < Vn; u++) {\n        if (mode == 0) {\n            sort(ch[u].begin(), ch[u].end(), [&](int a, int b) {\n                if (st.subD[a] != st.subD[b]) return st.subD[a] > st.subD[b];\n                return a < b;\n            });\n        } else {\n            sort(ch[u].begin(), ch[u].end(), [&](int a, int b) {\n                __int128 lhs = (__int128)st.subD[a] * st.sz[b];\n                __int128 rhs = (__int128)st.subD[b] * st.sz[a];\n                if (lhs != rhs) return lhs > rhs;\n                if (st.subD[a] != st.subD[b]) return st.subD[a] > st.subD[b];\n                return a < b;\n            });\n        }\n    }\n}\n\nComp build_global_route(const State& st, int orderMode) {\n    vector<vector<int>> ch;\n    build_children_sorted(st, ch, orderMode);\n\n    Comp C;\n    C.route.reserve(TREE_LEN);\n    C.pos.reserve(TREE_LEN + 1);\n    C.pos.push_back(0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        for (int c : ch[u]) {\n            C.route.push_back(move_char(u, c));\n            C.pos.push_back(c);\n            self(self, c);\n            C.route.push_back(move_char(c, u));\n            C.pos.push_back(u);\n        }\n    };\n    dfs(dfs, 0);\n\n    C.len = (int)C.route.size();\n    C.score = {st.num, TREE_LEN};\n    return C;\n}\n\nComp build_path_loop(int target) {\n    vector<int> fwd;\n    for (int x = target; x != 0; x = bfsParent[x]) fwd.push_back(x);\n    reverse(fwd.begin(), fwd.end());\n\n    Comp C;\n    C.pos.reserve(2 * (int)fwd.size() + 1);\n    C.pos.push_back(0);\n    for (int v : fwd) C.pos.push_back(v);\n    for (int i = (int)fwd.size() - 2; i >= 0; i--) C.pos.push_back(fwd[i]);\n    C.pos.push_back(0);\n\n    C.route.reserve((int)C.pos.size() - 1);\n    for (int i = 1; i < (int)C.pos.size(); i++) C.route.push_back(move_char(C.pos[i - 1], C.pos[i]));\n    C.len = (int)C.route.size();\n    return C;\n}\n\nComp build_subtree_loop(const State& st, int rootSub, int orderMode) {\n    vector<vector<int>> ch;\n    build_children_sorted(st, ch, orderMode);\n\n    vector<int> path;\n    for (int x = rootSub; x != 0; x = st.parent[x]) path.push_back(x);\n    reverse(path.begin(), path.end());\n\n    Comp C;\n    C.pos.reserve(2 * (st.depth[rootSub] + st.sz[rootSub] - 1) + 3);\n    C.pos.push_back(0);\n    for (int v : path) C.pos.push_back(v);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        for (int c : ch[u]) {\n            C.pos.push_back(c);\n            self(self, c);\n            C.pos.push_back(u);\n        }\n    };\n    dfs(dfs, rootSub);\n\n    for (int i = (int)path.size() - 2; i >= 0; i--) C.pos.push_back(path[i]);\n    C.pos.push_back(0);\n\n    C.route.reserve((int)C.pos.size() - 1);\n    for (int i = 1; i < (int)C.pos.size(); i++) C.route.push_back(move_char(C.pos[i - 1], C.pos[i]));\n    C.len = (int)C.route.size();\n    return C;\n}\n\nScore evaluate_positions(const vector<int>& pos) {\n    int L = (int)pos.size() - 1;\n    fill(firstOcc, firstOcc + Vn, -1);\n    fill(gapAcc, gapAcc + Vn, 0LL);\n\n    long long num = 0;\n    for (int t = 1; t <= L; t++) {\n        int x = pos[t];\n        if (firstOcc[x] == -1) {\n            firstOcc[x] = t;\n        } else {\n            long long g = t - lastOcc[x];\n            gapAcc[x] += g * (g - 1) / 2;\n        }\n        lastOcc[x] = t;\n    }\n    for (int x = 0; x < Vn; x++) {\n        if (firstOcc[x] == -1) return {INF64, L};\n        long long g = firstOcc[x] + L - lastOcc[x];\n        gapAcc[x] += g * (g - 1) / 2;\n        num += gapAcc[x] * 1LL * dirtv[x];\n    }\n    return {num, L};\n}\n\nScore evaluate_combo1(const Comp& H, int k, const Comp& B) {\n    static vector<int> pos;\n    pos.clear();\n    pos.reserve(1 + k * H.len + B.len);\n    pos.push_back(0);\n    for (int rep = 0; rep < k; rep++) pos.insert(pos.end(), H.pos.begin() + 1, H.pos.end());\n    pos.insert(pos.end(), B.pos.begin() + 1, B.pos.end());\n    return evaluate_positions(pos);\n}\n\nvector<int> make_k_list(int limit) {\n    vector<int> ks;\n    ks.push_back(0);\n    for (int k = 1; k <= min(limit, 10); k++) ks.push_back(k);\n    for (int k = 16; k <= limit; ) {\n        ks.push_back(k);\n        int nk = k + max(2, k / 2);\n        if (nk == k) nk++;\n        k = nk;\n    }\n    if (limit > 0) ks.push_back(limit);\n    sort(ks.begin(), ks.end());\n    ks.erase(unique(ks.begin(), ks.end()), ks.end());\n    return ks;\n}\n\nvoid add_refine(vector<int>& ks, int limit, int center) {\n    int L = max(0, center - 8);\n    int R = min(limit, center + 8);\n    for (int k = L; k <= R; k++) ks.push_back(k);\n    sort(ks.begin(), ks.end());\n    ks.erase(unique(ks.begin(), ks.end()), ks.end());\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<string> h(N - 1), vwall(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vwall[i];\n\n    Vn = N * N;\n    TREE_LEN = 2 * (Vn - 1);\n    for (int i = 0; i < Vn; i++) g[i].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> dirtv[vid(i, j)];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int a = vid(i, j);\n            if (i + 1 < N && h[i][j] == '0') {\n                int b = vid(i + 1, j);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int b = vid(i, j + 1);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n        }\n    }\n\n    for (int u = 0; u < Vn; u++) sqrtv_[u] = llround(1000.0 * sqrt((double)dirtv[u]));\n    for (int u = 0; u < Vn; u++) {\n        long long s1 = 0, s2 = 0;\n        for (int to : g[u]) {\n            s1 += dirtv[to];\n            s2 += sqrtv_[to];\n        }\n        imp1[u] = dirtv[u];\n        imp2[u] = sqrtv_[u];\n        imp3[u] = 100LL * dirtv[u] + 35LL * s1;\n        imp4[u] = 100LL * sqrtv_[u] + 35LL * s2;\n    }\n\n    compute_root_bfs();\n    global_start_time = chrono::steady_clock::now();\n\n    const double DESCENT_END = 1.00;\n    const double SEARCH_END  = 1.42;\n    const double INTENS_END  = 1.60;\n    const double FINAL_END   = 1.80;\n\n    vector<const long long*> imps = {imp1, imp2, imp3, imp4};\n    vector<int> sptRaw = gen_spt(imp3);\n    vector<int> sptSqrt = gen_spt(imp4);\n    vector<int> staticHot = make_static_hot_list();\n\n    vector<State> initStates;\n    initStates.reserve(64);\n\n    auto add_init_parent = [&](const vector<int>& parent) {\n        initStates.push_back(build_state(parent));\n    };\n\n    add_init_parent(sptRaw);\n    add_init_parent(sptSqrt);\n\n    for (const long long* imp : imps) {\n        for (long long nz : {0LL, 4000LL, 15000LL, 50000LL}) {\n            int reps = (nz == 0 ? 1 : 2);\n            for (int rep = 0; rep < reps; rep++) add_init_parent(gen_weighted_dfs(imp, nz));\n        }\n        for (long long nz : {0LL, 6000LL, 20000LL}) {\n            for (int pen : {0, 120, 300}) add_init_parent(gen_prim(imp, nz, pen));\n        }\n    }\n\n    sort(initStates.begin(), initStates.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n\n    vector<State> pool;\n    State best = initStates[0];\n    consider_pool(pool, best);\n\n    auto steepest_descent = [&](State st, double time_limit, int step_limit) -> State {\n        int steps = 0;\n        while (elapsed_sec() < time_limit && steps < step_limit) {\n            long long bestDelta = 0;\n            int bestu = -1, bestw = -1;\n            long long bestTie = LLONG_MIN;\n\n            for (int u = 1; u < Vn; u++) {\n                int pu = st.parent[u];\n                for (int w : g[u]) {\n                    if (w == pu) continue;\n                    if (is_descendant(st, w, u)) continue;\n\n                    long long delta = delta_reparent(st, u, w);\n                    long long tie = 1LL * (dirtv[w] - dirtv[pu]) * 1000 - st.depth[w];\n\n                    if (delta < bestDelta || (delta == bestDelta && tie > bestTie)) {\n                        bestDelta = delta;\n                        bestTie = tie;\n                        bestu = u;\n                        bestw = w;\n                    }\n                }\n            }\n\n            if (bestu == -1) break;\n            st.parent[bestu] = bestw;\n            st = build_state(st.parent);\n            steps++;\n        }\n        return st;\n    };\n\n    auto perturb_state = [&](const State& base) -> State {\n        State st = base;\n        int kicks = 1 + rng.next_int(2);\n\n        for (int rep = 0; rep < kicks; rep++) {\n            vector<int> topBad = make_top_bad(st, 60);\n            vector<char> usedU(Vn, 0);\n\n            struct MoveCand {\n                long long delta;\n                int u, w;\n                long long key;\n            };\n            vector<MoveCand> cands;\n            cands.reserve(256);\n\n            auto add_u = [&](int u) {\n                if (u <= 0 || u >= Vn || usedU[u]) return;\n                usedU[u] = 1;\n                int pu = st.parent[u];\n                for (int w : g[u]) {\n                    if (w == pu) continue;\n                    if (is_descendant(st, w, u)) continue;\n                    long long delta = delta_reparent(st, u, w);\n                    long long key = 1LL * (dirtv[w] - dirtv[pu]) * 1000 - st.depth[w];\n                    cands.push_back({delta, u, w, key});\n                }\n            };\n\n            for (int i = 0; i < (int)topBad.size() && i < 30; i++) add_u(topBad[i]);\n            for (int i = 0; i < (int)staticHot.size() && i < 20; i++) add_u(staticHot[i]);\n            for (int i = 0; i < 16; i++) add_u(1 + rng.next_int(Vn - 1));\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const MoveCand& A, const MoveCand& B) {\n                if (A.delta != B.delta) return A.delta < B.delta;\n                return A.key > B.key;\n            });\n\n            int pickLim = min(6, (int)cands.size());\n            int idx = rng.next_int(pickLim);\n            st.parent[cands[idx].u] = cands[idx].w;\n            st = build_state(st.parent);\n        }\n        return st;\n    };\n\n    int seedCount = min((int)initStates.size(), 8);\n    for (int i = 0; i < seedCount && elapsed_sec() < DESCENT_END; i++) {\n        State st = steepest_descent(initStates[i], DESCENT_END, 60);\n        consider_pool(pool, st);\n        if (st.num < best.num) best = st;\n    }\n\n    while (elapsed_sec() < SEARCH_END) {\n        State base;\n        if (!pool.empty() && rng.next_int(100) < 85) {\n            base = pool[rng.next_int(min(3, (int)pool.size()))];\n        } else {\n            const long long* imp = imps[rng.next_int((int)imps.size())];\n            if (rng.next_int(2) == 0) {\n                static const long long noises[] = {0, 4000, 15000, 50000};\n                base = build_state(gen_weighted_dfs(imp, noises[rng.next_int(4)]));\n            } else {\n                static const long long noises[] = {0, 6000, 20000};\n                static const int pens[] = {0, 120, 300};\n                base = build_state(gen_prim(imp, noises[rng.next_int(3)], pens[rng.next_int(3)]));\n            }\n        }\n\n        State pert = perturb_state(base);\n        State st = steepest_descent(pert, SEARCH_END, 36);\n        consider_pool(pool, st);\n        if (st.num < best.num) best = st;\n    }\n\n    if (elapsed_sec() < INTENS_END) {\n        best = steepest_descent(best, INTENS_END, 80);\n        consider_pool(pool, best);\n    }\n\n    sort(pool.begin(), pool.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n\n    // Final exact route construction: lightweight version\n    vector<State> finalStates;\n    for (int i = 0; i < (int)pool.size() && i < 3; i++) finalStates.push_back(pool[i]);\n    if (finalStates.empty()) finalStates.push_back(best);\n\n    vector<Comp> globals;\n    unordered_set<uint64_t> seenGlobal;\n    auto add_global = [&](const State& st, int mode) {\n        Comp C = build_global_route(st, mode);\n        uint64_t h = hash_route(C.route);\n        if (seenGlobal.insert(h).second) globals.push_back(move(C));\n    };\n\n    for (const State& st : finalStates) {\n        add_global(st, 0);\n        add_global(st, 1);\n    }\n\n    sort(globals.begin(), globals.end(), [&](const Comp& a, const Comp& b) {\n        return better_score(a.score, b.score);\n    });\n    if ((int)globals.size() > 6) globals.resize(6);\n\n    Score answerScore = globals[0].score;\n    string answerRoute = globals[0].route;\n\n    vector<Comp> loops;\n    unordered_set<uint64_t> seenLoop;\n\n    auto add_loop = [&](Comp&& C) {\n        if (C.len <= 0 || C.len >= 100000) return;\n        uint64_t h = hash_route(C.route);\n        if (seenLoop.insert(h).second) loops.push_back(move(C));\n    };\n\n    int loopStates = min(2, (int)finalStates.size());\n    for (int si = 0; si < loopStates && elapsed_sec() < FINAL_END; si++) {\n        const State& st = finalStates[si];\n\n        vector<pair<long long, int>> cand1;\n        for (int u = 1; u < Vn; u++) {\n            if (distRoot[u] <= 6) {\n                long long k1 = 1LL * dirtv[u] * 1000000LL / ((distRoot[u] + 1) * (distRoot[u] + 1));\n                long long k2 = sqrtv_[u] * 1000000LL / ((distRoot[u] + 1) * (distRoot[u] + 1));\n                cand1.push_back({max(k1, k2), u});\n            }\n        }\n        sort(cand1.begin(), cand1.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        for (int i = 0; i < (int)cand1.size() && i < 5; i++) {\n            Comp H = build_path_loop(cand1[i].second);\n            if (H.len <= 16) add_loop(move(H));\n        }\n\n        vector<pair<long long, int>> cand2;\n        for (int u = 1; u < Vn; u++) {\n            int len = 2 * (st.depth[u] + st.sz[u] - 1);\n            if (len <= 40 && st.depth[u] <= 8) {\n                long long key = st.subD[u] * 1000000LL / max(1, len * len);\n                cand2.push_back({key, u});\n            }\n        }\n        sort(cand2.begin(), cand2.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        for (int i = 0; i < (int)cand2.size() && i < 5; i++) {\n            add_loop(build_subtree_loop(st, cand2[i].second, 0));\n        }\n    }\n\n    if (elapsed_sec() < FINAL_END) {\n        vector<pair<long long, int>> rankL;\n        for (int i = 0; i < (int)loops.size(); i++) {\n            rankL.push_back({-(long long)loops[i].len, i});\n        }\n        sort(rankL.begin(), rankL.end());\n        vector<Comp> shortLoops;\n        for (int i = 0; i < (int)rankL.size() && i < 6; i++) shortLoops.push_back(loops[rankL[i].second]);\n        loops.swap(shortLoops);\n    }\n\n    int baseTry = min(3, (int)globals.size());\n    int loopTry = min(6, (int)loops.size());\n\n    for (int bi = 0; bi < baseTry && elapsed_sec() < FINAL_END; bi++) {\n        const Comp& B = globals[bi];\n        for (int hi = 0; hi < loopTry && elapsed_sec() < FINAL_END; hi++) {\n            const Comp& H = loops[hi];\n            int limit = (100000 - B.len) / H.len;\n            if (limit <= 0) continue;\n\n            vector<int> ks = make_k_list(limit);\n            int bestK = 0;\n            Score localBest = B.score;\n\n            for (int k : ks) {\n                Score sc = (k == 0 ? B.score : evaluate_combo1(H, k, B));\n                if (better_score(sc, localBest)) {\n                    localBest = sc;\n                    bestK = k;\n                }\n            }\n\n            add_refine(ks, limit, bestK);\n            for (int k : ks) {\n                Score sc = (k == 0 ? B.score : evaluate_combo1(H, k, B));\n                if (better_score(sc, localBest)) {\n                    localBest = sc;\n                    bestK = k;\n                }\n            }\n\n            if (bestK > 0 && better_score(localBest, answerScore)) {\n                answerScore = localBest;\n                string route;\n                route.reserve(bestK * H.len + B.len);\n                for (int rep = 0; rep < bestK; rep++) route += H.route;\n                route += B.route;\n                answerRoute = move(route);\n            }\n        }\n    }\n\n    if (answerRoute.empty() || (int)answerRoute.size() > 100000) {\n        answerRoute = build_global_route(best, 0).route;\n    }\n\n    cout << answerRoute << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"Ofast,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool same(int a, int b) { return find(a) == find(b); }\n    bool unite(int a, int b) {\n        a = find(a); b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int PMAX = 225;\n    static constexpr int MMAX = 200;\n    static constexpr int INF = 1e9;\n\n    int N, M;\n    int si, sj, startPos;\n\n    vector<string> board;\n    vector<string> words;\n    vector<array<int, 5>> w;\n\n    array<vector<int>, 26> occ;\n    int man[PMAX][PMAX];\n\n    int ov[MMAX][MMAX];\n    int lastc[MMAX];\n    int endCnt[MMAX];\n\n    struct MatInfo {\n        vector<uint16_t> a; // row-major\n    };\n    vector<MatInfo> mats; // [26][M][5]\n\n    vector<vector<uint16_t>> startVec;\n    int startApprox[MMAX];\n    int edgeApprox[MMAX][MMAX];\n    int bestOutApprox[MMAX];\n\n    uint32_t baseSeed = 1;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 1.88;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n    inline bool timeup(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline MatInfo& MAT(int c, int j, int st) {\n        return mats[(c * M + j) * 5 + st];\n    }\n    inline const MatInfo& MAT(int c, int j, int st) const {\n        return mats[(c * M + j) * 5 + st];\n    }\n\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        cin >> si >> sj;\n        startPos = si * N + sj;\n\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n\n        words.resize(M);\n        w.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) w[i][k] = words[i][k] - 'A';\n            lastc[i] = w[i][4];\n        }\n    }\n\n    void buildSeed() {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (auto& row : board) for (char c : row) mix((uint64_t)c);\n        for (auto& s : words) for (char c : s) mix((uint64_t)c);\n        baseSeed = (uint32_t)(h ^ (h >> 32));\n        if (baseSeed == 0) baseSeed = 1;\n        rng.seed(baseSeed);\n    }\n\n    void precomputeKeyboard() {\n        for (auto& v : occ) v.clear();\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                occ[board[i][j] - 'A'].push_back(id);\n            }\n        }\n        for (int p = 0; p < N * N; p++) {\n            int pi = p / N, pj = p % N;\n            for (int q = 0; q < N * N; q++) {\n                int qi = q / N, qj = q % N;\n                man[p][q] = abs(pi - qi) + abs(pj - qj);\n            }\n        }\n        for (int i = 0; i < M; i++) endCnt[i] = (int)occ[lastc[i]].size();\n    }\n\n    int calcOverlap(const string& a, const string& b) const {\n        for (int len = 4; len >= 1; len--) {\n            bool ok = true;\n            for (int k = 0; k < len; k++) {\n                if (a[5 - len + k] != b[k]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return len;\n        }\n        return 0;\n    }\n\n    void precomputeOverlaps() {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                ov[i][j] = (i == j ? 0 : calcOverlap(words[i], words[j]));\n            }\n        }\n    }\n\n    vector<uint16_t> buildMatFromSources(const vector<int>& srcPos, int wid, int st) {\n        int R = (int)srcPos.size();\n        int C = endCnt[wid];\n        vector<uint16_t> res(R * C);\n\n        int prevCost[PMAX], curCost[PMAX];\n\n        for (int r = 0; r < R; r++) {\n            int src = srcPos[r];\n\n            int prevChar = w[wid][st];\n            int pcnt = (int)occ[prevChar].size();\n            const vector<int>& firstPos = occ[prevChar];\n            for (int i = 0; i < pcnt; i++) {\n                prevCost[i] = man[src][firstPos[i]] + 1;\n            }\n\n            for (int k = st + 1; k < 5; k++) {\n                int curChar = w[wid][k];\n                const vector<int>& prevPos = occ[prevChar];\n                const vector<int>& curPos = occ[curChar];\n                int ccnt = (int)curPos.size();\n\n                for (int ci = 0; ci < ccnt; ci++) {\n                    int q = curPos[ci];\n                    int best = INF;\n                    for (int pi = 0; pi < pcnt; pi++) {\n                        int cand = prevCost[pi] + man[prevPos[pi]][q] + 1;\n                        if (cand < best) best = cand;\n                    }\n                    curCost[ci] = best;\n                }\n                for (int i = 0; i < ccnt; i++) prevCost[i] = curCost[i];\n                pcnt = ccnt;\n                prevChar = curChar;\n            }\n\n            for (int e = 0; e < C; e++) {\n                res[r * C + e] = (uint16_t)prevCost[e];\n            }\n        }\n        return res;\n    }\n\n    void precomputeMatrices() {\n        mats.resize(26 * M * 5);\n        startVec.assign(M, {});\n\n        for (int j = 0; j < M; j++) {\n            vector<int> src = {startPos};\n            auto v = buildMatFromSources(src, j, 0);\n            startVec[j].assign(v.begin(), v.end());\n\n            int mn = INF, sum = 0;\n            for (uint16_t x : startVec[j]) {\n                mn = min(mn, (int)x);\n                sum += x;\n            }\n            int avg = sum / max(1, (int)startVec[j].size());\n            startApprox[j] = (mn + avg) / 2;\n        }\n\n        for (int c = 0; c < 26; c++) {\n            for (int j = 0; j < M; j++) {\n                for (int st = 0; st < 5; st++) {\n                    MAT(c, j, st).a = buildMatFromSources(occ[c], j, st);\n                }\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            edgeApprox[i][i] = INF / 4;\n            for (int j = 0; j < M; j++) if (i != j) {\n                int c = lastc[i];\n                int st = ov[i][j];\n                const auto& arr = MAT(c, j, st).a;\n                int rows = (int)occ[c].size();\n                int cols = endCnt[j];\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                const uint16_t* p = arr.data();\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    const uint16_t* row = p + r * cols;\n                    for (int e = 0; e < cols; e++) {\n                        int v = row[e];\n                        if (v < rowMin) rowMin = v;\n                        if (v < globalMin) globalMin = v;\n                    }\n                    sumRowMin += rowMin;\n                }\n                int avgRowMin = (int)(sumRowMin / max(1, rows));\n                edgeApprox[i][j] = (globalMin + avgRowMin) / 2;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            int best = INF;\n            for (int j = 0; j < M; j++) if (i != j) {\n                best = min(best, edgeApprox[i][j]);\n            }\n            bestOutApprox[i] = best;\n        }\n    }\n\n    int evalPerm(const vector<int>& perm) const {\n        if (perm.empty()) return 0;\n\n        int dp[PMAX], ndp[PMAX];\n        int first = perm[0];\n        int cnt = endCnt[first];\n        for (int e = 0; e < cnt; e++) dp[e] = startVec[first][e];\n\n        for (int idx = 1; idx < (int)perm.size(); idx++) {\n            int a = perm[idx - 1];\n            int b = perm[idx];\n            int c = lastc[a];\n            int st = ov[a][b];\n            const auto& arr = MAT(c, b, st).a;\n            int rows = (int)occ[c].size();\n            int cols = endCnt[b];\n\n            for (int e = 0; e < cols; e++) ndp[e] = INF;\n            const uint16_t* matp = arr.data();\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const uint16_t* row = matp + r * cols;\n                for (int e = 0; e < cols; e++) {\n                    int cand = base + row[e];\n                    if (cand < ndp[e]) ndp[e] = cand;\n                }\n            }\n\n            cnt = cols;\n            for (int e = 0; e < cnt; e++) dp[e] = ndp[e];\n        }\n\n        int ans = INF;\n        for (int e = 0; e < cnt; e++) ans = min(ans, dp[e]);\n        return ans;\n    }\n\n    int transitionCostAndDP(const int* dp, int curWord, int nextWord, int* outDP) const {\n        int c = lastc[curWord];\n        int st = ov[curWord][nextWord];\n        const auto& arr = MAT(c, nextWord, st).a;\n        int rows = (int)occ[c].size();\n        int cols = endCnt[nextWord];\n\n        for (int e = 0; e < cols; e++) outDP[e] = INF;\n        const uint16_t* matp = arr.data();\n\n        for (int r = 0; r < rows; r++) {\n            int base = dp[r];\n            const uint16_t* row = matp + r * cols;\n            for (int e = 0; e < cols; e++) {\n                int cand = base + row[e];\n                if (cand < outDP[e]) outDP[e] = cand;\n            }\n        }\n\n        int best = INF;\n        for (int e = 0; e < cols; e++) best = min(best, outDP[e]);\n        return best;\n    }\n\n    string buildString(const vector<int>& perm) const {\n        string s;\n        if (perm.empty()) return s;\n        s.reserve(5 * (int)perm.size());\n        s += words[perm[0]];\n        for (int i = 1; i < (int)perm.size(); i++) {\n            int o = ov[perm[i - 1]][perm[i]];\n            s.append(words[perm[i]].begin() + o, words[perm[i]].end());\n        }\n        return s;\n    }\n\n    // ---------- Initial constructions ----------\n\n    vector<int> initGreedyAppend(int firstWord, uint32_t seed, bool randomized, int topNext = 4) const {\n        mt19937 rr(seed);\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> used(M, 0);\n\n        int curDP[PMAX], tmpDP[PMAX], chosenDP[PMAX];\n\n        perm.push_back(firstWord);\n        used[firstWord] = 1;\n        int curCnt = endCnt[firstWord];\n        for (int e = 0; e < curCnt; e++) curDP[e] = startVec[firstWord][e];\n        int curWord = firstWord;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                int score2;\n                int scoreExact;\n                int j;\n            };\n            vector<Cand> cand;\n            cand.reserve(M - (int)perm.size());\n\n            int remain = M - (int)perm.size();\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                int scoreExact = transitionCostAndDP(curDP, curWord, j, tmpDP);\n                int future = (remain > 1 ? bestOutApprox[j] / 2 : 0);\n                int score2 = scoreExact + future;\n                cand.push_back({score2, scoreExact, j});\n            }\n            sort(cand.begin(), cand.end(), [](const Cand& a, const Cand& b) {\n                if (a.score2 != b.score2) return a.score2 < b.score2;\n                if (a.scoreExact != b.scoreExact) return a.scoreExact < b.scoreExact;\n                return a.j < b.j;\n            });\n\n            int pickIdx = 0;\n            if (randomized) {\n                int lim = min<int>(topNext, cand.size());\n                pickIdx = uniform_int_distribution<int>(0, lim - 1)(rr);\n            }\n            int nxt = cand[pickIdx].j;\n\n            transitionCostAndDP(curDP, curWord, nxt, chosenDP);\n            curCnt = endCnt[nxt];\n            for (int e = 0; e < curCnt; e++) curDP[e] = chosenDP[e];\n\n            perm.push_back(nxt);\n            used[nxt] = 1;\n            curWord = nxt;\n        }\n        return perm;\n    }\n\n    vector<int> initEdgeGreedy(uint32_t seed, bool randomized) const {\n        struct E {\n            int u, v, cost, ovv;\n        };\n        vector<E> edges;\n        edges.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) if (i != j) {\n                edges.push_back({i, j, edgeApprox[i][j], ov[i][j]});\n            }\n        }\n\n        mt19937 rr(seed);\n        if (randomized) shuffle(edges.begin(), edges.end(), rr);\n\n        stable_sort(edges.begin(), edges.end(), [&](const E& a, const E& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.ovv != b.ovv) return a.ovv > b.ovv;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        vector<int> in(M, -1), out(M, -1);\n        DSU dsu(M);\n        int used = 0;\n        for (auto& e : edges) {\n            if (out[e.u] != -1) continue;\n            if (in[e.v] != -1) continue;\n            if (dsu.same(e.u, e.v)) continue;\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n            used++;\n            if (used == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) if (in[i] == -1) {\n            head = i;\n            break;\n        }\n\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> seen(M, 0);\n        int cur = head;\n        while (cur != -1 && !seen[cur]) {\n            perm.push_back(cur);\n            seen[cur] = 1;\n            cur = out[cur];\n        }\n        for (int i = 0; i < M; i++) if (!seen[i]) perm.push_back(i);\n        return perm;\n    }\n\n    vector<int> initExactInsertion(uint32_t seed, bool randomized) const {\n        mt19937 rr(seed);\n\n        if (M == 1) return {0};\n\n        struct PairCand {\n            int approx;\n            int a, b;\n        };\n        vector<PairCand> pairs;\n        pairs.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) if (i != j) {\n                pairs.push_back({startApprox[i] + edgeApprox[i][j], i, j});\n            }\n        }\n        sort(pairs.begin(), pairs.end(), [](const PairCand& x, const PairCand& y) {\n            if (x.approx != y.approx) return x.approx < y.approx;\n            if (x.a != y.a) return x.a < y.a;\n            return x.b < y.b;\n        });\n\n        int pairKeep = randomized ? 14 : 8;\n        pairKeep = min<int>(pairKeep, pairs.size());\n\n        vector<pair<int, pair<int, int>>> exactPairs;\n        for (int t = 0; t < pairKeep; t++) {\n            vector<int> p = {pairs[t].a, pairs[t].b};\n            int ex = evalPerm(p);\n            exactPairs.push_back({ex, {pairs[t].a, pairs[t].b}});\n        }\n        sort(exactPairs.begin(), exactPairs.end());\n\n        int choosePair = 0;\n        if (randomized) {\n            int lim = min<int>(3, exactPairs.size());\n            choosePair = uniform_int_distribution<int>(0, lim - 1)(rr);\n        }\n\n        vector<int> perm = {exactPairs[choosePair].second.first, exactPairs[choosePair].second.second};\n        vector<char> used(M, 0);\n        used[perm[0]] = used[perm[1]] = 1;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                int inc;\n                int x, pos;\n            };\n            vector<Cand> global;\n            int keepPerX = randomized ? 2 : 1;\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                vector<Cand> bests;\n                bests.reserve(keepPerX + 2);\n\n                auto push = [&](Cand c) {\n                    bests.push_back(c);\n                    sort(bests.begin(), bests.end(), [](const Cand& a, const Cand& b) {\n                        if (a.inc != b.inc) return a.inc < b.inc;\n                        if (a.x != b.x) return a.x < b.x;\n                        return a.pos < b.pos;\n                    });\n                    if ((int)bests.size() > keepPerX) bests.pop_back();\n                };\n\n                push({startApprox[x] + edgeApprox[x][perm[0]] - startApprox[perm[0]], x, 0});\n                for (int i = 1; i < (int)perm.size(); i++) {\n                    int inc = edgeApprox[perm[i - 1]][x] + edgeApprox[x][perm[i]] - edgeApprox[perm[i - 1]][perm[i]];\n                    push({inc, x, i});\n                }\n                push({edgeApprox[perm.back()][x], x, (int)perm.size()});\n\n                for (auto& c : bests) global.push_back(c);\n            }\n\n            sort(global.begin(), global.end(), [](const Cand& a, const Cand& b) {\n                if (a.inc != b.inc) return a.inc < b.inc;\n                if (a.x != b.x) return a.x < b.x;\n                return a.pos < b.pos;\n            });\n\n            int globalKeep = randomized ? 14 : 8;\n            globalKeep = min<int>(globalKeep, global.size());\n\n            vector<Cand> exactBest;\n            for (int t = 0; t < globalKeep; t++) {\n                auto c = global[t];\n                vector<int> np = perm;\n                np.insert(np.begin() + c.pos, c.x);\n                int ex = evalPerm(np);\n                exactBest.push_back({ex, c.x, c.pos});\n            }\n\n            sort(exactBest.begin(), exactBest.end(), [](const Cand& a, const Cand& b) {\n                if (a.inc != b.inc) return a.inc < b.inc;\n                if (a.x != b.x) return a.x < b.x;\n                return a.pos < b.pos;\n            });\n\n            int choose = 0;\n            if (randomized) {\n                int lim = min<int>(2, exactBest.size());\n                choose = uniform_int_distribution<int>(0, lim - 1)(rr);\n            }\n\n            auto c = exactBest[choose];\n            perm.insert(perm.begin() + c.pos, c.x);\n            used[c.x] = 1;\n        }\n\n        return perm;\n    }\n\n    // ---------- Approx deltas ----------\n\n    inline long long linkApprox(int prev, int cur) const {\n        if (cur == -1) return 0;\n        if (prev == -1) return startApprox[cur];\n        return edgeApprox[prev][cur];\n    }\n\n    long long blockRelocateDelta(const vector<int>& p, int a, int len, int b) const {\n        int n = (int)p.size();\n        int x0 = p[a];\n        int x1 = p[a + len - 1];\n        int A = (a > 0 ? p[a - 1] : -1);\n        int B = (a + len < n ? p[a + len] : -1);\n\n        auto qAt = [&](int idx) -> int {\n            if (idx < a) return p[idx];\n            return p[idx + len];\n        };\n\n        int qSize = n - len;\n        int C = (b > 0 ? qAt(b - 1) : -1);\n        int D = (b < qSize ? qAt(b) : -1);\n\n        long long delta = 0;\n        delta -= linkApprox(A, x0);\n        delta -= linkApprox(x1, B);\n        delta += linkApprox(A, B);\n\n        delta -= linkApprox(C, D);\n        delta += linkApprox(C, x0);\n        delta += linkApprox(x1, D);\n\n        return delta;\n    }\n\n    long long swapDelta(const vector<int>& p, int a, int b) const {\n        if (a == b) return 0;\n        if (a > b) swap(a, b);\n        int n = (int)p.size();\n\n        int A = p[a], B = p[b];\n        int pA = (a > 0 ? p[a - 1] : -1);\n        int nA = (a + 1 < n ? p[a + 1] : -1);\n        int pB = (b > 0 ? p[b - 1] : -1);\n        int nB = (b + 1 < n ? p[b + 1] : -1);\n\n        long long oldCost = 0, newCost = 0;\n\n        if (a + 1 == b) {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, A);\n            newCost += linkApprox(A, nB);\n        } else {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, nA);\n            oldCost += linkApprox(pB, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, nA);\n            newCost += linkApprox(pB, A);\n            newCost += linkApprox(A, nB);\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyBlockRelocate(vector<int>& p, int a, int len, int b) const {\n        vector<int> block(p.begin() + a, p.begin() + a + len);\n        p.erase(p.begin() + a, p.begin() + a + len);\n        p.insert(p.begin() + b, block.begin(), block.end());\n    }\n\n    void applyMove(vector<int>& p, int type, int a, int b) const {\n        // 0: relocate len1\n        // 1: relocate len2\n        // 2: relocate len3\n        // 3: swap\n        if (type == 0) applyBlockRelocate(p, a, 1, b);\n        else if (type == 1) applyBlockRelocate(p, a, 2, b);\n        else if (type == 2) applyBlockRelocate(p, a, 3, b);\n        else swap(p[a], p[b]);\n    }\n\n    struct MoveCand {\n        long long d;\n        int type, a, b;\n    };\n\n    pair<vector<int>, int> localSearch(vector<int> perm, int curExact, int maxIter, int topK) {\n        int n = (int)perm.size();\n\n        for (int iter = 0; iter < maxIter && !timeup(0.06); iter++) {\n            vector<MoveCand> cand;\n            cand.reserve(n * n + max(0, (n - 1) * (n - 1)) + max(0, (n - 2) * (n - 2)) + n * (n - 1) / 2);\n\n            // relocate len 1\n            for (int a = 0; a < n; a++) {\n                for (int b = 0; b <= n - 1; b++) {\n                    if (b == a) continue;\n                    long long d = blockRelocateDelta(perm, a, 1, b);\n                    cand.push_back({d, 0, a, b});\n                }\n            }\n\n            // relocate len 2\n            if (n >= 2) {\n                for (int a = 0; a + 1 < n; a++) {\n                    for (int b = 0; b <= n - 2; b++) {\n                        if (b == a) continue;\n                        long long d = blockRelocateDelta(perm, a, 2, b);\n                        cand.push_back({d, 1, a, b});\n                    }\n                }\n            }\n\n            // relocate len 3\n            if (n >= 3) {\n                for (int a = 0; a + 2 < n; a++) {\n                    for (int b = 0; b <= n - 3; b++) {\n                        if (b == a) continue;\n                        long long d = blockRelocateDelta(perm, a, 3, b);\n                        cand.push_back({d, 2, a, b});\n                    }\n                }\n            }\n\n            // swap\n            for (int a = 0; a < n; a++) {\n                for (int b = a + 1; b < n; b++) {\n                    long long d = swapDelta(perm, a, b);\n                    cand.push_back({d, 3, a, b});\n                }\n            }\n\n            auto comp = [](const MoveCand& x, const MoveCand& y) {\n                if (x.d != y.d) return x.d < y.d;\n                if (x.type != y.type) return x.type < y.type;\n                if (x.a != y.a) return x.a < y.a;\n                return x.b < y.b;\n            };\n\n            int K = min<int>(topK, cand.size());\n            if (K == 0) break;\n            if (K < (int)cand.size()) {\n                nth_element(cand.begin(), cand.begin() + K, cand.end(), comp);\n                cand.resize(K);\n            }\n            sort(cand.begin(), cand.end(), comp);\n\n            bool improved = false;\n            int bestExact = curExact;\n            vector<int> bestPerm;\n\n            for (auto& mv : cand) {\n                if (timeup(0.05)) break;\n                vector<int> np = perm;\n                applyMove(np, mv.type, mv.a, mv.b);\n                int ex = evalPerm(np);\n                if (ex < bestExact) {\n                    bestExact = ex;\n                    bestPerm.swap(np);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            perm.swap(bestPerm);\n            curExact = bestExact;\n        }\n\n        return {perm, curExact};\n    }\n\n    // ---------- Cheap exact polishing ----------\n\n    pair<vector<int>, int> polishTriples(vector<int> perm, int curExact, int passes) {\n        int n = (int)perm.size();\n        if (n < 3) return {perm, curExact};\n\n        for (int pass = 0; pass < passes && !timeup(0.10); pass++) {\n            bool any = false;\n            for (int l = 0; l + 3 <= n && !timeup(0.10); l++) {\n                array<int, 3> cur = {perm[l], perm[l + 1], perm[l + 2]};\n                vector<int> base = {cur[0], cur[1], cur[2]};\n                sort(base.begin(), base.end());\n\n                int bestEx = curExact;\n                array<int, 3> bestSeg = cur;\n\n                do {\n                    array<int, 3> seg = {base[0], base[1], base[2]};\n                    if (seg == cur) continue;\n                    vector<int> np = perm;\n                    np[l] = seg[0];\n                    np[l + 1] = seg[1];\n                    np[l + 2] = seg[2];\n                    int ex = evalPerm(np);\n                    if (ex < bestEx) {\n                        bestEx = ex;\n                        bestSeg = seg;\n                    }\n                } while (next_permutation(base.begin(), base.end()));\n\n                if (bestEx < curExact) {\n                    perm[l] = bestSeg[0];\n                    perm[l + 1] = bestSeg[1];\n                    perm[l + 2] = bestSeg[2];\n                    curExact = bestEx;\n                    any = true;\n                }\n            }\n            if (!any) break;\n        }\n\n        return {perm, curExact};\n    }\n\n    pair<vector<int>, int> polishQuads(vector<int> perm, int curExact, int passes) {\n        int n = (int)perm.size();\n        if (n < 4) return {perm, curExact};\n\n        for (int pass = 0; pass < passes && !timeup(0.08); pass++) {\n            bool any = false;\n            for (int l = 0; l + 4 <= n && !timeup(0.08); l++) {\n                array<int, 4> cur = {perm[l], perm[l + 1], perm[l + 2], perm[l + 3]};\n                vector<int> base = {cur[0], cur[1], cur[2], cur[3]};\n                sort(base.begin(), base.end());\n\n                int bestEx = curExact;\n                array<int, 4> bestSeg = cur;\n\n                do {\n                    array<int, 4> seg = {base[0], base[1], base[2], base[3]};\n                    if (seg == cur) continue;\n                    vector<int> np = perm;\n                    np[l] = seg[0];\n                    np[l + 1] = seg[1];\n                    np[l + 2] = seg[2];\n                    np[l + 3] = seg[3];\n                    int ex = evalPerm(np);\n                    if (ex < bestEx) {\n                        bestEx = ex;\n                        bestSeg = seg;\n                    }\n                } while (next_permutation(base.begin(), base.end()));\n\n                if (bestEx < curExact) {\n                    perm[l] = bestSeg[0];\n                    perm[l + 1] = bestSeg[1];\n                    perm[l + 2] = bestSeg[2];\n                    perm[l + 3] = bestSeg[3];\n                    curExact = bestEx;\n                    any = true;\n                }\n            }\n            if (!any) break;\n        }\n\n        return {perm, curExact};\n    }\n\n    // ---------- ILS ----------\n\n    void randomKick(vector<int>& perm, mt19937& rr, int cnt) const {\n        int n = (int)perm.size();\n        for (int t = 0; t < cnt; t++) {\n            int typ = uniform_int_distribution<int>(0, 3)(rr);\n            if (typ == 0) {\n                int a = uniform_int_distribution<int>(0, n - 1)(rr);\n                int b = uniform_int_distribution<int>(0, n - 1)(rr);\n                if (a != b) swap(perm[a], perm[b]);\n            } else if (typ == 1) {\n                int a = uniform_int_distribution<int>(0, n - 1)(rr);\n                int b = uniform_int_distribution<int>(0, n - 1)(rr);\n                applyBlockRelocate(perm, a, 1, b);\n            } else if (typ == 2) {\n                if (n >= 2) {\n                    int a = uniform_int_distribution<int>(0, n - 2)(rr);\n                    int b = uniform_int_distribution<int>(0, n - 2)(rr);\n                    applyBlockRelocate(perm, a, 2, b);\n                }\n            } else {\n                if (n >= 3) {\n                    int a = uniform_int_distribution<int>(0, n - 3)(rr);\n                    int b = uniform_int_distribution<int>(0, n - 3)(rr);\n                    applyBlockRelocate(perm, a, 3, b);\n                }\n            }\n        }\n    }\n\n    // ---------- Final exact path ----------\n\n    pair<int, vector<int>> exactPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n\n        const auto& firstPos = occ[s[0] - 'A'];\n        vector<int> dpPrev(firstPos.size());\n        parent[0].assign(firstPos.size(), -1);\n        for (int i = 0; i < (int)firstPos.size(); i++) {\n            dpPrev[i] = man[startPos][firstPos[i]] + 1;\n        }\n\n        for (int t = 1; t < L; t++) {\n            const auto& prevPos = occ[s[t - 1] - 'A'];\n            const auto& curPos = occ[s[t] - 'A'];\n            vector<int> dpCur(curPos.size(), INF);\n            parent[t].assign(curPos.size(), -1);\n\n            for (int ci = 0; ci < (int)curPos.size(); ci++) {\n                int q = curPos[ci];\n                int best = INF, bestp = -1;\n                for (int pi = 0; pi < (int)prevPos.size(); pi++) {\n                    int cand = dpPrev[pi] + man[prevPos[pi]][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bestp = pi;\n                    }\n                }\n                dpCur[ci] = best;\n                parent[t][ci] = bestp;\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        int best = INF, idx = -1;\n        for (int i = 0; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < best) {\n                best = dpPrev[i];\n                idx = i;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = occ[s[L - 1] - 'A'][idx];\n        for (int t = L - 1; t >= 1; t--) {\n            idx = parent[t][idx];\n            path[t - 1] = occ[s[t - 1] - 'A'][idx];\n        }\n        return {best, path};\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        readInput();\n        buildSeed();\n        precomputeKeyboard();\n        precomputeOverlaps();\n        precomputeMatrices();\n\n        vector<int> startOrder(M);\n        iota(startOrder.begin(), startOrder.end(), 0);\n        sort(startOrder.begin(), startOrder.end(), [&](int a, int b) {\n            if (startApprox[a] != startApprox[b]) return startApprox[a] < startApprox[b];\n            return a < b;\n        });\n\n        struct SeedCand {\n            vector<int> perm;\n            int exact;\n        };\n        vector<SeedCand> seeds;\n\n        auto addSeed = [&](vector<int> p) {\n            int ex = evalPerm(p);\n            seeds.push_back({move(p), ex});\n        };\n\n        // exact greedy append\n        addSeed(initGreedyAppend(startOrder[0], baseSeed + 11, false));\n        if (M >= 2) addSeed(initGreedyAppend(startOrder[1], baseSeed + 12, false));\n        if (M >= 3) addSeed(initGreedyAppend(startOrder[2], baseSeed + 13, false));\n\n        {\n            mt19937 rr(baseSeed + 100);\n            int lim = min(10, M);\n            for (int z = 0; z < 4 && !timeup(0.55); z++) {\n                int first = startOrder[uniform_int_distribution<int>(0, lim - 1)(rr)];\n                addSeed(initGreedyAppend(first, baseSeed + 21 + z, true));\n            }\n        }\n\n        // exact-informed insertion\n        if (!timeup(0.45)) addSeed(initExactInsertion(baseSeed + 31, false));\n        if (!timeup(0.45)) addSeed(initExactInsertion(baseSeed + 32, true));\n        if (!timeup(0.42)) addSeed(initExactInsertion(baseSeed + 33, true));\n\n        // complementary seed\n        if (!timeup(0.38)) addSeed(initEdgeGreedy(baseSeed + 41, false));\n        if (!timeup(0.36)) addSeed(initEdgeGreedy(baseSeed + 42, true));\n\n        sort(seeds.begin(), seeds.end(), [](const SeedCand& a, const SeedCand& b) {\n            return a.exact < b.exact;\n        });\n\n        vector<int> bestPerm = seeds[0].perm;\n        int bestExact = seeds[0].exact;\n\n        int topSeedCnt = min<int>(4, seeds.size());\n        for (int i = 0; i < topSeedCnt && !timeup(0.24); i++) {\n            int K = (elapsed() < 1.02 ? 2200 : 1600);\n            auto cur = localSearch(seeds[i].perm, seeds[i].exact, 7, K);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        // cheap exact polishing on the current best\n        if (!timeup(0.18)) {\n            auto cur = polishTriples(bestPerm, bestExact, 2);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        if (!timeup(0.14)) {\n            auto cur = polishQuads(bestPerm, bestExact, 1);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        if (!timeup(0.11)) {\n            auto cur = localSearch(bestPerm, bestExact, 3, 1350);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        // Iterated local search from the current best\n        mt19937 rr(baseSeed + 999);\n        int noImprove = 0;\n        while (!timeup(0.08)) {\n            vector<int> p = bestPerm;\n            int kickCnt = (noImprove < 3 ? 2 : (noImprove < 7 ? 4 : 6));\n            randomKick(p, rr, kickCnt);\n            int ex = evalPerm(p);\n\n            int K = (elapsed() < 1.42 ? 1150 : 700);\n            auto cur = localSearch(move(p), ex, 4, K);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n                noImprove = 0;\n\n                if (!timeup(0.07)) {\n                    auto pol = polishTriples(bestPerm, bestExact, 1);\n                    if (pol.second < bestExact) {\n                        bestExact = pol.second;\n                        bestPerm = move(pol.first);\n                    }\n                }\n            } else {\n                noImprove++;\n                if (noImprove >= 8 && elapsed() > 1.58) break;\n            }\n        }\n\n        string finalS = buildString(bestPerm);\n        auto [finalCost, path] = exactPathForString(finalS);\n\n        for (int pos : path) {\n            cout << (pos / N) << ' ' << (pos % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXQ = 160;\nstatic constexpr int WORDS = 7;   // 7*64 = 448 >= 400\nstatic constexpr int MAXD_BEAM = 64;\n\nusing ull = unsigned long long;\nusing Mask = array<ull, WORDS>;\n\nstruct Placement {\n    int di = 0, dj = 0;\n    Mask mask{};\n    array<unsigned char, MAXQ> contrib{};\n};\n\nstruct Field {\n    int sz = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> pls;\n};\n\nstruct State {\n    vector<int> choice;\n    array<short, MAXQ> setsum{};\n    vector<short> drillsum;\n    int pen = 0;\n    double div = 0.0;\n};\n\nstruct WeightedStates {\n    bool plausible = false;\n    int bestPen = INT_MAX;\n    vector<int> idx;\n    vector<double> w;\n    double sumW = 0.0;\n};\n\nstruct UnionSummary {\n    bool hasPlausible = false;\n    int bestPen = INT_MAX;\n    int distinctUnionCount = 0;\n\n    vector<Mask> masks;\n    vector<double> weights;\n\n    Mask bestMask{};\n    Mask must1{};\n    Mask maybe1{};\n\n    double bestWeight = 0.0;\n\n    vector<int> ambiguous;\n\n    vector<double> supportProb;\n    vector<double> supportVar;\n    vector<double> countVar;\n\n    double maxCellScore = -1.0;\n    int bestCell = -1;\n};\n\nstruct Solver {\n    int N, M, NN;\n    double eps, alpha;\n    int totalArea = 0;\n    int maxOps, ops = 0;\n\n    vector<Field> fields;\n\n    int Qcur = 0;\n    vector<vector<int>> queryCells;\n    vector<Mask> queryMasks;\n    vector<int> qSize, qResp;\n    vector<char> qKnown;\n    vector<vector<double>> qScore;\n\n    vector<array<int,4>> cellQids;\n\n    vector<int> drilledCells, drilledObs;\n    vector<int> cellObs;\n    vector<char> drilledFlag;\n\n    vector<State> pool;\n    vector<Mask> rejectedMasks;\n\n    vector<Mask> rowParityMask, colParityMask, checkerMask, rowMod3Mask, colMod3Mask;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point stTime;\n    double compLog2 = 0.0;\n    int adaptiveQueriesUsed = 0;\n    int exactBeamRuns = 0;\n\n    Solver(): rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    // ---------- mask helpers ----------\n    static inline void mask_clear(Mask &m) { m.fill(0); }\n    static inline void mask_set(Mask &m, int idx) { m[idx >> 6] |= (1ULL << (idx & 63)); }\n    static inline bool mask_test(const Mask &m, int idx) { return (m[idx >> 6] >> (idx & 63)) & 1ULL; }\n    static inline void mask_or_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] |= b[i]; }\n    static inline void mask_and_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] &= b[i]; }\n    static inline Mask mask_and(const Mask &a, const Mask &b) { Mask c = a; mask_and_eq(c, b); return c; }\n    static inline Mask mask_xor(const Mask &a, const Mask &b) {\n        Mask c{};\n        for (int i = 0; i < WORDS; i++) c[i] = a[i] ^ b[i];\n        return c;\n    }\n    static inline Mask mask_andnot(const Mask &a, const Mask &b) {\n        Mask c{};\n        for (int i = 0; i < WORDS; i++) c[i] = a[i] & ~b[i];\n        return c;\n    }\n    static inline int mask_popcount(const Mask &m) {\n        int s = 0;\n        for (int i = 0; i < WORDS; i++) s += __builtin_popcountll(m[i]);\n        return s;\n    }\n    static inline int intersect_count(const Mask &a, const Mask &b) {\n        int s = 0;\n        for (int i = 0; i < WORDS; i++) s += __builtin_popcountll(a[i] & b[i]);\n        return s;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - stTime).count();\n    }\n\n    bool better(int p1, double d1, int p2, double d2) const {\n        if (p1 != p2) return p1 < p2;\n        return d1 + 1e-12 < d2;\n    }\n\n    int rand_int(int lim) {\n        return int(rng() % (uint64_t)lim);\n    }\n\n    int activeQCount() const {\n        int c = 0;\n        for (int q = 0; q < Qcur; q++) c += qKnown[q];\n        return c;\n    }\n\n    bool can_spend_ops(int extraOps) const {\n        int needFallback = (NN - (int)drilledCells.size()) + 1;\n        return ops + extraOps + needFallback <= maxOps;\n    }\n\n    bool is_rejected_mask(const Mask &m) const {\n        for (const auto &x : rejectedMasks) if (x == m) return true;\n        return false;\n    }\n\n    vector<int> cells_from_mask(const Mask &m) const {\n        vector<int> cells;\n        cells.reserve(mask_popcount(m));\n        for (int idx = 0; idx < NN; idx++) if (mask_test(m, idx)) cells.push_back(idx);\n        return cells;\n    }\n\n    // ---------- probability ----------\n    static double norm_cdf(double x) {\n        static const double INV_SQRT2 = 0.707106781186547524400844362104849039;\n        return 0.5 * erfc(-x * INV_SQRT2);\n    }\n\n    static double rounded_normal_nll(int y, double mu, double sigma) {\n        double prob;\n        if (sigma < 1e-12) {\n            int z = max(0, (int)llround(mu));\n            prob = (z == y ? 1.0 : 0.0);\n        } else if (y == 0) {\n            double hi = (0.5 - mu) / sigma;\n            prob = norm_cdf(hi);\n        } else {\n            double lo = (y - 0.5 - mu) / sigma;\n            double hi = (y + 0.5 - mu) / sigma;\n            prob = norm_cdf(hi) - norm_cdf(lo);\n        }\n        if (prob < 1e-300) prob = 1e-300;\n        return -log(prob);\n    }\n\n    // ---------- I/O ----------\n    void read_input() {\n        cin >> N >> M >> eps;\n        NN = N * N;\n        maxOps = 2 * NN;\n        alpha = 1.0 - 2.0 * eps;\n\n        fields.resize(M);\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            fields[k].sz = d;\n            fields[k].rel.resize(d);\n            int mxr = 0, mxc = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].rel[t] = {i, j};\n                mxr = max(mxr, i);\n                mxc = max(mxc, j);\n            }\n            fields[k].h = mxr + 1;\n            fields[k].w = mxc + 1;\n            totalArea += d;\n        }\n\n        cellObs.assign(NN, -1);\n        drilledFlag.assign(NN, 0);\n\n        queryCells.assign(MAXQ, {});\n        queryMasks.assign(MAXQ, {});\n        qSize.assign(MAXQ, 0);\n        qResp.assign(MAXQ, 0);\n        qKnown.assign(MAXQ, 0);\n        qScore.assign(MAXQ, vector<double>(totalArea + 1, 0.0));\n    }\n\n    int ask_set_query(const vector<int> &cells) {\n        cout << \"q \" << cells.size();\n        for (int idx : cells) cout << ' ' << (idx / N) << ' ' << (idx % N);\n        cout << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << ' ' << (idx % N) << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    bool answer_mask_raw(const Mask &mask) {\n        vector<int> cells;\n        cells.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) if (mask_test(mask, idx)) cells.push_back(idx);\n\n        cout << \"a \" << cells.size();\n        for (int idx : cells) cout << ' ' << (idx / N) << ' ' << (idx % N);\n        cout << '\\n' << flush;\n        int res;\n        cin >> res;\n        ops++;\n        return res == 1;\n    }\n\n    bool submit_guess(const Mask &mask) {\n        if (is_rejected_mask(mask)) return false;\n        bool ok = answer_mask_raw(mask);\n        if (!ok) rejectedMasks.push_back(mask);\n        return ok;\n    }\n\n    // ---------- setup ----------\n    void build_queries() {\n        // base queries:\n        // [0, N) row\n        // [N, 2N) col\n        // [2N, 2N+4) mod2\n        // [2N+4, 2N+13) mod3\n        Qcur = 2 * N + 13;\n        cellQids.resize(NN);\n\n        rowParityMask.assign(2, Mask{});\n        colParityMask.assign(2, Mask{});\n        checkerMask.assign(2, Mask{});\n        rowMod3Mask.assign(3, Mask{});\n        colMod3Mask.assign(3, Mask{});\n\n        for (auto &m : rowParityMask) mask_clear(m);\n        for (auto &m : colParityMask) mask_clear(m);\n        for (auto &m : checkerMask) mask_clear(m);\n        for (auto &m : rowMod3Mask) mask_clear(m);\n        for (auto &m : colMod3Mask) mask_clear(m);\n\n        for (int q = 0; q < Qcur; q++) {\n            queryCells[q].clear();\n            mask_clear(queryMasks[q]);\n        }\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int idx = i * N + j;\n                int q0 = i;\n                int q1 = N + j;\n                int q2 = 2 * N + (i & 1) * 2 + (j & 1);\n                int q3 = 2 * N + 4 + (i % 3) * 3 + (j % 3);\n                cellQids[idx] = {q0, q1, q2, q3};\n\n                queryCells[q0].push_back(idx);\n                queryCells[q1].push_back(idx);\n                queryCells[q2].push_back(idx);\n                queryCells[q3].push_back(idx);\n\n                mask_set(rowParityMask[i & 1], idx);\n                mask_set(colParityMask[j & 1], idx);\n                mask_set(checkerMask[(i + j) & 1], idx);\n                mask_set(rowMod3Mask[i % 3], idx);\n                mask_set(colMod3Mask[j % 3], idx);\n            }\n        }\n\n        for (int q = 0; q < Qcur; q++) {\n            for (int idx : queryCells[q]) mask_set(queryMasks[q], idx);\n            qSize[q] = (int)queryCells[q].size();\n        }\n    }\n\n    void precompute_placements() {\n        compLog2 = 0.0;\n        for (int k = 0; k < M; k++) {\n            auto &f = fields[k];\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                    mask_clear(p.mask);\n                    p.contrib.fill(0);\n\n                    for (auto [ri, rj] : f.rel) {\n                        int ai = di + ri;\n                        int aj = dj + rj;\n                        int idx = ai * N + aj;\n                        mask_set(p.mask, idx);\n                        auto &arr = cellQids[idx];\n                        for (int t = 0; t < 4; t++) p.contrib[arr[t]]++;\n                    }\n                    f.pls.push_back(p);\n                }\n            }\n            compLog2 += log2((double)max(1, (int)f.pls.size()));\n        }\n    }\n\n    void register_query_response(int q, int y) {\n        qKnown[q] = 1;\n        qResp[q] = y;\n\n        double sigma = sqrt((double)qSize[q] * eps * (1.0 - eps));\n        for (int v = 0; v <= totalArea; v++) {\n            double mu = eps * qSize[q] + alpha * v;\n            qScore[q][v] = rounded_normal_nll(y, mu, sigma);\n        }\n    }\n\n    void activate_queries(int l, int r) {\n        for (int q = l; q < r; q++) {\n            if (qKnown[q]) continue;\n            if (!can_spend_ops(1)) return;\n            int y = ask_set_query(queryCells[q]);\n            register_query_response(q, y);\n        }\n    }\n\n    bool add_adaptive_query(const Mask &m) {\n        int k = mask_popcount(m);\n        if (k < 2 || Qcur >= MAXQ) return false;\n        if (!can_spend_ops(1)) return false;\n        for (int q = 0; q < Qcur; q++) if (queryMasks[q] == m) return false;\n\n        int q = Qcur++;\n        queryMasks[q] = m;\n        queryCells[q] = cells_from_mask(m);\n        qSize[q] = k;\n\n        for (auto &f : fields) {\n            for (auto &pl : f.pls) {\n                pl.contrib[q] = (unsigned char)intersect_count(pl.mask, m);\n            }\n        }\n\n        int y = ask_set_query(queryCells[q]);\n        register_query_response(q, y);\n        adaptiveQueriesUsed++;\n        return true;\n    }\n\n    // ---------- state build / local search ----------\n    State build_state(const vector<int> &choice) {\n        State st;\n        st.choice = choice;\n        st.setsum.fill(0);\n\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[choice[k]];\n            for (int q = 0; q < Qcur; q++) st.setsum[q] += pl.contrib[q];\n        }\n\n        st.div = 0.0;\n        for (int q = 0; q < Qcur; q++) if (qKnown[q]) st.div += qScore[q][st.setsum[q]];\n\n        int D = (int)drilledCells.size();\n        st.drillsum.assign(D, 0);\n        st.pen = 0;\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int s = 0;\n            for (int k = 0; k < M; k++) s += (int)mask_test(fields[k].pls[choice[k]].mask, idx);\n            st.drillsum[t] = (short)s;\n            int d = s - drilledObs[t];\n            st.pen += d * d;\n        }\n        return st;\n    }\n\n    void apply_move(State &st, int k, int newPid) {\n        int oldPid = st.choice[k];\n        if (oldPid == newPid) return;\n\n        const auto &oldPl = fields[k].pls[oldPid];\n        const auto &newPl = fields[k].pls[newPid];\n\n        for (int q = 0; q < Qcur; q++) {\n            int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n            if (!diff) continue;\n            int oldv = st.setsum[q];\n            int newv = oldv + diff;\n            if (qKnown[q]) st.div += qScore[q][newv] - qScore[q][oldv];\n            st.setsum[q] = (short)newv;\n        }\n\n        int D = (int)drilledCells.size();\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n            if (!diff) continue;\n            int oldv = st.drillsum[t];\n            int newv = oldv + diff;\n            int before = oldv - drilledObs[t];\n            int after = newv - drilledObs[t];\n            st.pen += after * after - before * before;\n            st.drillsum[t] = (short)newv;\n        }\n\n        st.choice[k] = newPid;\n    }\n\n    void hill_climb(State &st, int sweeps) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            bool changed = false;\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int zz = 0; zz < M; zz++) {\n                int k = ord[zz];\n                int oldPid = st.choice[k];\n                const auto &oldPl = fields[k].pls[oldPid];\n                int bestPid = oldPid;\n                int bestPen = st.pen;\n                double bestDiv = st.div;\n\n                int D = (int)drilledCells.size();\n\n                for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                    if (pid == oldPid) continue;\n                    const auto &newPl = fields[k].pls[pid];\n\n                    int candPen = st.pen;\n                    double candDiv = st.div;\n\n                    for (int q = 0; q < Qcur; q++) {\n                        int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n                        if (!diff) continue;\n                        int oldv = st.setsum[q];\n                        int newv = oldv + diff;\n                        if (qKnown[q]) candDiv += qScore[q][newv] - qScore[q][oldv];\n                    }\n\n                    for (int t = 0; t < D; t++) {\n                        int idx = drilledCells[t];\n                        int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n                        if (!diff) continue;\n                        int oldv = st.drillsum[t];\n                        int newv = oldv + diff;\n                        int before = oldv - drilledObs[t];\n                        int after = newv - drilledObs[t];\n                        candPen += after * after - before * before;\n                    }\n\n                    if (better(candPen, candDiv, bestPen, bestDiv)) {\n                        bestPen = candPen;\n                        bestDiv = candDiv;\n                        bestPid = pid;\n                    }\n                }\n\n                if (bestPid != oldPid) {\n                    apply_move(st, k, bestPid);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> random_seed() {\n        vector<int> choice(M);\n        for (int k = 0; k < M; k++) choice[k] = rand_int((int)fields[k].pls.size());\n        return choice;\n    }\n\n    vector<int> greedy_seed() {\n        vector<int> choice(M, 0);\n        array<short, MAXQ> cur{};\n        cur.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int id = 0; id < M; id++) {\n            int k = ord[id];\n            int bestPid = 0;\n            double bestDelta = 1e100;\n\n            for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                const auto &pl = fields[k].pls[pid];\n                double delta = 0.0;\n                for (int q = 0; q < Qcur; q++) {\n                    if (!qKnown[q]) continue;\n                    int c = pl.contrib[q];\n                    if (!c) continue;\n                    int oldv = cur[q];\n                    int newv = oldv + c;\n                    delta += qScore[q][newv] - qScore[q][oldv];\n                }\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPid = pid;\n                }\n            }\n\n            choice[k] = bestPid;\n            const auto &pl = fields[k].pls[bestPid];\n            for (int q = 0; q < Qcur; q++) cur[q] += pl.contrib[q];\n        }\n        return choice;\n    }\n\n    vector<int> perturbed_seed() {\n        if (pool.empty()) return random_seed();\n        int baseCnt = min(6, (int)pool.size());\n        vector<int> choice = pool[rand_int(baseCnt)].choice;\n\n        int changes = 1 + rand_int(max(1, min(5, M)));\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int t = 0; t < changes; t++) {\n            int k = ord[t];\n            int sz = (int)fields[k].pls.size();\n            if (sz <= 1) continue;\n            int cur = choice[k];\n            int np = rand_int(sz - 1);\n            if (np >= cur) np++;\n            choice[k] = np;\n        }\n        return choice;\n    }\n\n    vector<int> crossover_seed() {\n        if ((int)pool.size() < 2) return random_seed();\n        int baseCnt = min(8, (int)pool.size());\n        int a = rand_int(baseCnt);\n        int b = rand_int(baseCnt - 1);\n        if (b >= a) b++;\n        vector<int> child(M);\n        ull r = rng();\n        for (int k = 0; k < M; k++) child[k] = ((r >> (k & 63)) & 1ULL) ? pool[a].choice[k] : pool[b].choice[k];\n        if (rand_int(3) == 0) {\n            int k = rand_int(M);\n            int sz = (int)fields[k].pls.size();\n            if (sz > 1) child[k] = rand_int(sz);\n        }\n        return child;\n    }\n\n    bool contains_choice(const vector<vector<int>> &vv, const vector<int> &x) {\n        for (const auto &v : vv) if (v == x) return true;\n        return false;\n    }\n\n    void optimize_pool(int randomCnt, int pertCnt, int sweeps, bool useGreedy) {\n        vector<vector<int>> seeds;\n\n        for (const auto &st : pool) {\n            if (!contains_choice(seeds, st.choice)) seeds.push_back(st.choice);\n        }\n\n        if (useGreedy) {\n            for (int t = 0; t < 6; t++) {\n                auto s = greedy_seed();\n                if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n            }\n        }\n\n        int crossCnt = min(8, max(0, (int)pool.size() - 1));\n        for (int t = 0; t < crossCnt; t++) {\n            auto s = crossover_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        for (int t = 0; t < pertCnt; t++) {\n            auto s = perturbed_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        for (int t = 0; t < randomCnt; t++) {\n            auto s = random_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        if (seeds.empty()) seeds.push_back(random_seed());\n\n        vector<State> cands;\n        cands.reserve(seeds.size());\n        for (auto &seed : seeds) {\n            State st = build_state(seed);\n            hill_climb(st, sweeps);\n            cands.push_back(move(st));\n        }\n\n        sort(cands.begin(), cands.end(), [&](const State &a, const State &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        pool.clear();\n        for (auto &st : cands) {\n            bool dup = false;\n            for (auto &kept : pool) {\n                if (kept.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) pool.push_back(move(st));\n            if ((int)pool.size() >= 28) break;\n        }\n    }\n\n    // ---------- exact / beam search ----------\n    bool exact_beam_merge() {\n        if (exactBeamRuns >= 3) return false;\n        if (elapsed() > 2.30) return false;\n        if (M > 9) return false;\n        if ((int)drilledCells.size() > MAXD_BEAM) return false;\n\n        vector<int> actQ;\n        for (int q = 0; q < Qcur; q++) if (qKnown[q]) actQ.push_back(q);\n        int AQ = (int)actQ.size();\n        int D = (int)drilledCells.size();\n        if (AQ == 0) return false;\n\n        vector<vector<int>> candP(M);\n        for (int k = 0; k < M; k++) {\n            auto &vec = candP[k];\n            vec.reserve(fields[k].pls.size());\n            for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                const auto &pl = fields[k].pls[pid];\n                bool ok = true;\n                for (int t = 0; t < D; t++) {\n                    if (drilledObs[t] == 0 && mask_test(pl.mask, drilledCells[t])) {\n                        ok = false;\n                        break;\n                    }\n                }\n                if (ok) vec.push_back(pid);\n            }\n            if (vec.empty()) return false;\n        }\n\n        double candLog = 0.0;\n        for (int k = 0; k < M; k++) candLog += log2((double)candP[k].size());\n        if ((M <= 6 && candLog > 82.0) ||\n            (M == 7 && candLog > 72.0) ||\n            (M == 8 && candLog > 64.0) ||\n            (M == 9 && candLog > 58.0)) {\n            return false;\n        }\n\n        int beamWidth = (M <= 5 ? 1600 : M <= 6 ? 1200 : M <= 7 ? 800 : 500);\n        int localKeep = (M <= 6 ? 24 : 16);\n        if (candLog > 68.0) beamWidth = max(300, beamWidth / 2);\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (candP[a].size() != candP[b].size()) return candP[a].size() < candP[b].size();\n            return fields[a].sz > fields[b].sz;\n        });\n\n        vector<vector<unsigned short>> fMinQ(M, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned short>> fMaxQ(M, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned char>> fMinD(M, vector<unsigned char>(D, 0));\n        vector<vector<unsigned char>> fMaxD(M, vector<unsigned char>(D, 0));\n\n        for (int pos = 0; pos < M; pos++) {\n            int k = order[pos];\n            for (int qi = 0; qi < AQ; qi++) {\n                int q = actQ[qi];\n                int mn = 1e9, mx = -1e9;\n                for (int pid : candP[k]) {\n                    int c = fields[k].pls[pid].contrib[q];\n                    mn = min(mn, c);\n                    mx = max(mx, c);\n                }\n                fMinQ[pos][qi] = (unsigned short)mn;\n                fMaxQ[pos][qi] = (unsigned short)mx;\n            }\n            for (int t = 0; t < D; t++) {\n                int mn = 1, mx = 0;\n                int idx = drilledCells[t];\n                for (int pid : candP[k]) {\n                    int c = mask_test(fields[k].pls[pid].mask, idx);\n                    mn = min(mn, c);\n                    mx = max(mx, c);\n                }\n                fMinD[pos][t] = (unsigned char)mn;\n                fMaxD[pos][t] = (unsigned char)mx;\n            }\n        }\n\n        vector<vector<unsigned short>> remMinQ(M + 1, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned short>> remMaxQ(M + 1, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned char>> remMinD(M + 1, vector<unsigned char>(D, 0));\n        vector<vector<unsigned char>> remMaxD(M + 1, vector<unsigned char>(D, 0));\n\n        for (int pos = M - 1; pos >= 0; pos--) {\n            for (int qi = 0; qi < AQ; qi++) {\n                remMinQ[pos][qi] = remMinQ[pos + 1][qi] + fMinQ[pos][qi];\n                remMaxQ[pos][qi] = remMaxQ[pos + 1][qi] + fMaxQ[pos][qi];\n            }\n            for (int t = 0; t < D; t++) {\n                remMinD[pos][t] = remMinD[pos + 1][t] + fMinD[pos][t];\n                remMaxD[pos][t] = remMaxD[pos + 1][t] + fMaxD[pos][t];\n            }\n        }\n\n        int TA = totalArea;\n        vector<vector<double>> rangeMin(AQ, vector<double>((TA + 1) * (TA + 1), 1e100));\n        for (int qi = 0; qi < AQ; qi++) {\n            int q = actQ[qi];\n            for (int l = 0; l <= TA; l++) {\n                double mn = 1e100;\n                for (int r = l; r <= TA; r++) {\n                    mn = min(mn, qScore[q][r]);\n                    rangeMin[qi][l * (TA + 1) + r] = mn;\n                }\n            }\n        }\n\n        struct BNode {\n            int penLB = 0;\n            double divLB = 0.0;\n            array<short, MAXQ> qsum{};\n            array<unsigned char, MAXD_BEAM> dsum{};\n            array<unsigned short, 20> choice{};\n        };\n\n        auto cmpNode = [&](const BNode &a, const BNode &b) {\n            if (a.penLB != b.penLB) return a.penLB < b.penLB;\n            return a.divLB < b.divLB;\n        };\n\n        vector<BNode> beam(1);\n        beam[0].qsum.fill(0);\n        beam[0].dsum.fill(0);\n        beam[0].choice.fill(0);\n\n        for (int pos = 0; pos < M; pos++) {\n            int k = order[pos];\n            vector<BNode> next;\n            next.reserve((int)beam.size() * localKeep);\n\n            for (const auto &cur : beam) {\n                vector<BNode> local;\n                local.reserve(candP[k].size());\n\n                for (int pid : candP[k]) {\n                    const auto &pl = fields[k].pls[pid];\n                    BNode nd = cur;\n                    nd.choice[pos] = (unsigned short)pid;\n\n                    for (int qi = 0; qi < AQ; qi++) {\n                        nd.qsum[qi] += pl.contrib[actQ[qi]];\n                    }\n                    for (int t = 0; t < D; t++) {\n                        nd.dsum[t] += (unsigned char)mask_test(pl.mask, drilledCells[t]);\n                    }\n\n                    int penlb = 0;\n                    for (int t = 0; t < D; t++) {\n                        int L = nd.dsum[t] + remMinD[pos + 1][t];\n                        int R = nd.dsum[t] + remMaxD[pos + 1][t];\n                        int obs = drilledObs[t];\n                        if (obs < L) {\n                            int d = L - obs;\n                            penlb += d * d;\n                        } else if (obs > R) {\n                            int d = obs - R;\n                            penlb += d * d;\n                        }\n                    }\n\n                    double divlb = 0.0;\n                    for (int qi = 0; qi < AQ; qi++) {\n                        int L = nd.qsum[qi] + remMinQ[pos + 1][qi];\n                        int R = nd.qsum[qi] + remMaxQ[pos + 1][qi];\n                        if (L < 0) L = 0;\n                        if (R > TA) R = TA;\n                        if (L > R) swap(L, R);\n                        divlb += rangeMin[qi][L * (TA + 1) + R];\n                    }\n\n                    nd.penLB = penlb;\n                    nd.divLB = divlb;\n                    local.push_back(move(nd));\n                }\n\n                if ((int)local.size() > localKeep) {\n                    partial_sort(local.begin(), local.begin() + localKeep, local.end(), cmpNode);\n                    local.resize(localKeep);\n                }\n                for (auto &x : local) next.push_back(move(x));\n            }\n\n            if (next.empty()) return false;\n            if ((int)next.size() > beamWidth) {\n                partial_sort(next.begin(), next.begin() + beamWidth, next.end(), cmpNode);\n                next.resize(beamWidth);\n            } else {\n                sort(next.begin(), next.end(), cmpNode);\n            }\n            beam.swap(next);\n\n            if (elapsed() > 2.55) break;\n        }\n\n        vector<State> exactStates;\n        int takeFinal = min(12, (int)beam.size());\n        for (int i = 0; i < takeFinal; i++) {\n            vector<int> choice(M);\n            for (int pos = 0; pos < M; pos++) choice[order[pos]] = beam[i].choice[pos];\n            exactStates.push_back(build_state(choice));\n        }\n\n        if (exactStates.empty()) return false;\n\n        vector<State> merged = pool;\n        for (auto &st : exactStates) {\n            bool dup = false;\n            for (auto &x : merged) {\n                if (x.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) merged.push_back(move(st));\n        }\n\n        sort(merged.begin(), merged.end(), [&](const State &a, const State &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        vector<State> uniq;\n        for (auto &st : merged) {\n            bool dup = false;\n            for (auto &u : uniq) {\n                if (u.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) uniq.push_back(move(st));\n            if ((int)uniq.size() >= 28) break;\n        }\n\n        bool improved = false;\n        if (pool.empty()) improved = true;\n        else if (!uniq.empty() && better(uniq[0].pen, uniq[0].div, pool[0].pen, pool[0].div)) improved = true;\n        pool.swap(uniq);\n        exactBeamRuns++;\n        return improved;\n    }\n\n    // ---------- drill bookkeeping ----------\n    void record_drill(int idx, int val) {\n        if (!drilledFlag[idx]) {\n            drilledFlag[idx] = 1;\n            cellObs[idx] = val;\n            drilledCells.push_back(idx);\n            drilledObs.push_back(val);\n        }\n    }\n\n    // ---------- summaries ----------\n    Mask union_of_choice(const vector<int> &choice) {\n        Mask u{};\n        mask_clear(u);\n        for (int k = 0; k < M; k++) mask_or_eq(u, fields[k].pls[choice[k]].mask);\n        return u;\n    }\n\n    vector<unsigned char> state_counts(const State &st) {\n        vector<unsigned char> cnt(NN, 0);\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[st.choice[k]];\n            for (auto [ri, rj] : fields[k].rel) {\n                int idx = (pl.di + ri) * N + (pl.dj + rj);\n                cnt[idx]++;\n            }\n        }\n        return cnt;\n    }\n\n    WeightedStates collect_weighted_states() {\n        WeightedStates ws;\n        if (pool.empty()) return ws;\n\n        vector<char> usable(pool.size(), 0);\n        for (int i = 0; i < (int)pool.size(); i++) {\n            Mask u = union_of_choice(pool[i].choice);\n            if (is_rejected_mask(u)) continue;\n            usable[i] = 1;\n            ws.bestPen = min(ws.bestPen, pool[i].pen);\n        }\n        if (ws.bestPen == INT_MAX) return ws;\n\n        int aq = max(1, activeQCount());\n\n        if (ws.bestPen == 0) {\n            double bestDiv = 1e100;\n            for (int i = 0; i < (int)pool.size(); i++) {\n                if (!usable[i]) continue;\n                if (pool[i].pen == 0) bestDiv = min(bestDiv, pool[i].div);\n            }\n\n            double margin = 8.0 + 0.30 * aq;\n            for (int i = 0; i < (int)pool.size(); i++) {\n                if (!usable[i]) continue;\n                if (pool[i].pen != 0) continue;\n                if (pool[i].div <= bestDiv + margin) {\n                    double w = exp(-min(50.0, (pool[i].div - bestDiv) / 2.5));\n                    ws.idx.push_back(i);\n                    ws.w.push_back(w);\n                    ws.sumW += w;\n                }\n            }\n            ws.plausible = !ws.idx.empty();\n        }\n\n        if (!ws.plausible) {\n            vector<int> ids;\n            for (int i = 0; i < (int)pool.size(); i++) if (usable[i]) ids.push_back(i);\n            int take = min(14, (int)ids.size());\n\n            double base = 1e100;\n            vector<double> obj(take);\n            for (int t = 0; t < take; t++) {\n                int i = ids[t];\n                obj[t] = pool[i].div + 20.0 * pool[i].pen;\n                base = min(base, obj[t]);\n            }\n            for (int t = 0; t < take; t++) {\n                int i = ids[t];\n                double w = exp(-min(50.0, (obj[t] - base) / 4.0));\n                ws.idx.push_back(i);\n                ws.w.push_back(w);\n                ws.sumW += w;\n            }\n        }\n\n        if (ws.sumW <= 0.0) {\n            ws.sumW = (double)ws.w.size();\n            for (double &x : ws.w) x = 1.0;\n        }\n        return ws;\n    }\n\n    void compute_cell_stats(const WeightedStates &ws,\n                            vector<double> &supportProb,\n                            vector<double> &supportVar,\n                            vector<double> &countVar) {\n        supportProb.assign(NN, 0.0);\n        supportVar.assign(NN, 0.0);\n        countVar.assign(NN, 0.0);\n        if (ws.idx.empty()) return;\n\n        vector<double> meanCnt(NN, 0.0), sqCnt(NN, 0.0);\n\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            const State &st = pool[ws.idx[t]];\n            double w = ws.w[t];\n            vector<unsigned char> cnt = state_counts(st);\n\n            for (int idx = 0; idx < NN; idx++) {\n                double c = cnt[idx];\n                if (c > 0) supportProb[idx] += w;\n                meanCnt[idx] += w * c;\n                sqCnt[idx] += w * c * c;\n            }\n        }\n\n        for (int idx = 0; idx < NN; idx++) {\n            supportProb[idx] /= ws.sumW;\n            double p = supportProb[idx];\n            supportVar[idx] = p * (1.0 - p);\n\n            meanCnt[idx] /= ws.sumW;\n            sqCnt[idx] /= ws.sumW;\n            countVar[idx] = max(0.0, sqCnt[idx] - meanCnt[idx] * meanCnt[idx]);\n        }\n    }\n\n    UnionSummary summarize_unions() {\n        UnionSummary us;\n        if (pool.empty()) return us;\n\n        WeightedStates ws = collect_weighted_states();\n        us.hasPlausible = ws.plausible;\n        us.bestPen = ws.bestPen;\n        if (ws.idx.empty()) return us;\n\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            Mask u = union_of_choice(pool[ws.idx[t]].choice);\n            double w = ws.w[t];\n            int pos = -1;\n            for (int i = 0; i < (int)us.masks.size(); i++) {\n                if (us.masks[i] == u) {\n                    pos = i;\n                    break;\n                }\n            }\n            if (pos == -1) {\n                us.masks.push_back(u);\n                us.weights.push_back(w);\n            } else {\n                us.weights[pos] += w;\n            }\n        }\n\n        us.distinctUnionCount = (int)us.masks.size();\n        if (us.masks.empty()) return us;\n\n        double sumW = 0.0;\n        for (double w : us.weights) sumW += w;\n        if (sumW <= 0.0) {\n            sumW = (double)us.weights.size();\n            for (double &w : us.weights) w = 1.0;\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)us.weights.size(); i++) {\n            if (us.weights[i] > us.weights[bestIdx]) bestIdx = i;\n        }\n        us.bestMask = us.masks[bestIdx];\n        us.bestWeight = us.weights[bestIdx] / sumW;\n\n        if (us.hasPlausible) {\n            us.must1 = us.masks[0];\n            us.maybe1 = us.masks[0];\n            for (int i = 1; i < (int)us.masks.size(); i++) {\n                mask_and_eq(us.must1, us.masks[i]);\n                mask_or_eq(us.maybe1, us.masks[i]);\n            }\n            Mask amb = mask_xor(us.must1, us.maybe1);\n            for (int idx = 0; idx < NN; idx++) if (mask_test(amb, idx)) us.ambiguous.push_back(idx);\n        }\n\n        compute_cell_stats(ws, us.supportProb, us.supportVar, us.countVar);\n\n        us.maxCellScore = -1.0;\n        us.bestCell = -1;\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            for (int idx : us.ambiguous) {\n                if (drilledFlag[idx]) continue;\n                double sc = us.supportVar[idx] + 0.15 * min(1.0, us.countVar[idx]);\n                if (sc > us.maxCellScore + 1e-15) {\n                    us.maxCellScore = sc;\n                    us.bestCell = idx;\n                }\n            }\n        }\n\n        if (us.bestCell == -1) {\n            for (int idx = 0; idx < NN; idx++) {\n                if (drilledFlag[idx]) continue;\n                double sc = 0.8 * us.supportVar[idx] + 0.2 * min(1.0, us.countVar[idx]);\n                if (sc > us.maxCellScore + 1e-15) {\n                    us.maxCellScore = sc;\n                    us.bestCell = idx;\n                }\n            }\n        }\n\n        return us;\n    }\n\n    // ---------- answering / fallback ----------\n    Mask consensus_answer_mask(const UnionSummary &us) {\n        Mask ans = us.must1;\n        for (int idx = 0; idx < NN; idx++) if (cellObs[idx] > 0) mask_set(ans, idx);\n        return ans;\n    }\n\n    bool try_answer_strong(double weightThreshold, bool allowLowVar) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (is_rejected_mask(us.bestMask)) return false;\n\n        bool ok = false;\n        if (us.distinctUnionCount == 1) ok = true;\n        else if (us.bestWeight >= weightThreshold) ok = true;\n        else if (allowLowVar && us.bestWeight >= 0.90 && us.maxCellScore >= 0.0 && us.maxCellScore < 0.01) ok = true;\n\n        if (!ok) return false;\n        if (!can_spend_ops(1)) return false;\n        return submit_guess(us.bestMask);\n    }\n\n    bool try_dual_guess(double minBestWeight, int minNeedForTwoGuesses) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (us.distinctUnionCount != 2) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n\n        if (!(us.bestWeight >= minBestWeight || need >= minNeedForTwoGuesses)) return false;\n        if (!can_spend_ops(2)) return false;\n\n        vector<int> ord = {0, 1};\n        if (us.weights[1] > us.weights[0]) swap(ord[0], ord[1]);\n\n        for (int id : ord) {\n            if (is_rejected_mask(us.masks[id])) continue;\n            if (submit_guess(us.masks[id])) return true;\n        }\n        return false;\n    }\n\n    bool try_one_last_best_guess() {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (is_rejected_mask(us.bestMask)) return false;\n        if (!can_spend_ops(1)) return false;\n        return submit_guess(us.bestMask);\n    }\n\n    void full_drill_and_answer() {\n        for (int idx = 0; idx < NN; idx++) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n        Mask ans{};\n        mask_clear(ans);\n        for (int idx = 0; idx < NN; idx++) if (cellObs[idx] > 0) mask_set(ans, idx);\n        answer_mask_raw(ans);\n    }\n\n    bool try_small_ambiguous_finish(int limitUndrilled) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (collect_weighted_states().bestPen != 0) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n\n        if (need == 0) {\n            if (!us.ambiguous.empty()) return false;\n            if (!can_spend_ops(1)) return false;\n            Mask ans = consensus_answer_mask(us);\n            return submit_guess(ans);\n        }\n\n        if (need > limitUndrilled) return false;\n        if (ops + need + 1 > maxOps) return false;\n\n        for (int idx : us.ambiguous) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n\n        if (elapsed() < 2.45) optimize_pool(4, 10, 4, false);\n        if (elapsed() < 2.30) exact_beam_merge();\n\n        auto us2 = summarize_unions();\n        if (!us2.hasPlausible) return false;\n        if (collect_weighted_states().bestPen != 0) return false;\n        if (!us2.ambiguous.empty()) {\n            if (try_dual_guess(0.85, 6)) return true;\n            return false;\n        }\n\n        if (!can_spend_ops(1)) return false;\n        Mask ans = consensus_answer_mask(us2);\n        return submit_guess(ans);\n    }\n\n    bool speculative_guess() {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (collect_weighted_states().bestPen != 0) return false;\n        if (is_rejected_mask(us.bestMask)) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n\n        bool go = false;\n        if (us.bestWeight >= 0.90) go = true;\n        if (us.distinctUnionCount <= 2 && need <= 10) go = true;\n        if (!go) return false;\n        if (!can_spend_ops(1)) return false;\n\n        return submit_guess(us.bestMask);\n    }\n\n    // ---------- adaptive discriminative queries ----------\n    int predicted_sum_on_mask(const State &st, const Mask &m) {\n        int s = 0;\n        for (int k = 0; k < M; k++) s += intersect_count(fields[k].pls[st.choice[k]].mask, m);\n        return s;\n    }\n\n    double evaluate_candidate_query(const Mask &m, const WeightedStates &ws) {\n        int k = mask_popcount(m);\n        if (k < 2 || ws.idx.empty()) return -1e100;\n\n        double mean = 0.0, sq = 0.0;\n        int mn = INT_MAX, mx = INT_MIN;\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            int pred = predicted_sum_on_mask(pool[ws.idx[t]], m);\n            mn = min(mn, pred);\n            mx = max(mx, pred);\n            double w = ws.w[t] / ws.sumW;\n            mean += w * pred;\n            sq += w * pred * pred;\n        }\n        if (mx == mn) return -1e100;\n\n        double varState = max(0.0, sq - mean * mean);\n        double noise = k * eps * (1.0 - eps) + 0.25;\n        return (varState / (noise + 1e-9)) * sqrt((double)k);\n    }\n\n    void add_candidate_mask(vector<Mask> &cand, const Mask &m) {\n        int k = mask_popcount(m);\n        if (k < 2) return;\n        for (const auto &x : cand) if (x == m) return;\n        for (int q = 0; q < Qcur; q++) if (queryMasks[q] == m) return;\n        cand.push_back(m);\n    }\n\n    vector<Mask> generate_candidate_masks(const UnionSummary &us, const WeightedStates &ws) {\n        vector<Mask> cand;\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            Mask amb = mask_xor(us.must1, us.maybe1);\n            add_candidate_mask(cand, amb);\n\n            add_candidate_mask(cand, mask_and(amb, rowParityMask[0]));\n            add_candidate_mask(cand, mask_and(amb, rowParityMask[1]));\n            add_candidate_mask(cand, mask_and(amb, colParityMask[0]));\n            add_candidate_mask(cand, mask_and(amb, colParityMask[1]));\n            add_candidate_mask(cand, mask_and(amb, checkerMask[0]));\n            add_candidate_mask(cand, mask_and(amb, checkerMask[1]));\n\n            if (mask_popcount(amb) >= 10) {\n                for (int r = 0; r < 3; r++) add_candidate_mask(cand, mask_and(amb, rowMod3Mask[r]));\n                for (int c = 0; c < 3; c++) add_candidate_mask(cand, mask_and(amb, colMod3Mask[c]));\n            }\n\n            vector<pair<int,int>> rows, cols;\n            for (int i = 0; i < N; i++) {\n                int cnt = 0;\n                for (int idx : queryCells[i]) cnt += mask_test(amb, idx);\n                if (cnt >= 2) rows.push_back({cnt, i});\n            }\n            for (int j = 0; j < N; j++) {\n                int cnt = 0;\n                for (int idx : queryCells[N + j]) cnt += mask_test(amb, idx);\n                if (cnt >= 2) cols.push_back({cnt, j});\n            }\n            sort(rows.rbegin(), rows.rend());\n            sort(cols.rbegin(), cols.rend());\n            for (int t = 0; t < min(4, (int)rows.size()); t++) add_candidate_mask(cand, mask_and(amb, queryMasks[rows[t].second]));\n            for (int t = 0; t < min(4, (int)cols.size()); t++) add_candidate_mask(cand, mask_and(amb, queryMasks[N + cols[t].second]));\n        }\n\n        if (us.masks.size() >= 2) {\n            int b1 = 0, b2 = -1;\n            for (int i = 1; i < (int)us.weights.size(); i++) {\n                if (us.weights[i] > us.weights[b1]) {\n                    b2 = b1;\n                    b1 = i;\n                } else if (b2 == -1 || us.weights[i] > us.weights[b2]) {\n                    b2 = i;\n                }\n            }\n            if (b2 != -1) {\n                add_candidate_mask(cand, mask_xor(us.masks[b1], us.masks[b2]));\n                add_candidate_mask(cand, mask_andnot(us.masks[b1], us.masks[b2]));\n                add_candidate_mask(cand, mask_andnot(us.masks[b2], us.masks[b1]));\n            }\n        }\n\n        vector<int> ord;\n        ord.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) if (!drilledFlag[idx]) ord.push_back(idx);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (us.supportVar[a] != us.supportVar[b]) return us.supportVar[a] > us.supportVar[b];\n            return us.countVar[a] > us.countVar[b];\n        });\n\n        int take = min((int)ord.size(), max(12, min(64, 2 * N + 12)));\n        Mask topU{};\n        mask_clear(topU);\n        for (int i = 0; i < take; i++) mask_set(topU, ord[i]);\n        add_candidate_mask(cand, topU);\n        add_candidate_mask(cand, mask_and(topU, checkerMask[0]));\n        add_candidate_mask(cand, mask_and(topU, checkerMask[1]));\n        add_candidate_mask(cand, mask_and(topU, rowParityMask[0]));\n        add_candidate_mask(cand, mask_and(topU, rowParityMask[1]));\n\n        for (int rep = 0; rep < 6; rep++) {\n            Mask h{};\n            mask_clear(h);\n            ull a = rng() | 1ULL;\n            ull b = rng() | 1ULL;\n            ull c = rng();\n            for (int i = 0; i < take; i++) {\n                int idx = ord[i];\n                ull z = a * (ull)(idx + 1) + b * (ull)((idx / N) + 131 * (idx % N) + 7) + c;\n                if ((z >> 63) & 1ULL) mask_set(h, idx);\n            }\n            add_candidate_mask(cand, h);\n            add_candidate_mask(cand, mask_andnot(topU, h));\n        }\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            for (int rep = 0; rep < 6; rep++) {\n                Mask h{};\n                mask_clear(h);\n                ull a = (rng() % 7) * 2 + 1;\n                ull b = (rng() % 7) * 2 + 1;\n                ull c = rng() & 3;\n                for (int idx : us.ambiguous) {\n                    int i = idx / N, j = idx % N;\n                    if ((((a * (ull)i + b * (ull)j + c) & 3ULL) < 2ULL)) mask_set(h, idx);\n                }\n                add_candidate_mask(cand, h);\n            }\n        }\n\n        vector<int> rank(ws.idx.size());\n        iota(rank.begin(), rank.end(), 0);\n        sort(rank.begin(), rank.end(), [&](int a, int b) { return ws.w[a] > ws.w[b]; });\n        int T = min(6, (int)rank.size());\n\n        vector<vector<unsigned char>> cnts;\n        for (int t = 0; t < T; t++) cnts.push_back(state_counts(pool[ws.idx[rank[t]]]));\n\n        for (int a = 0; a < T; a++) {\n            for (int b = a + 1; b < T; b++) {\n                Mask gt{}, lt{}, sdiff{}, bigdiff{};\n                mask_clear(gt); mask_clear(lt); mask_clear(sdiff); mask_clear(bigdiff);\n                for (int idx = 0; idx < NN; idx++) {\n                    int ca = cnts[a][idx];\n                    int cb = cnts[b][idx];\n                    if (ca > cb) mask_set(gt, idx);\n                    if (ca < cb) mask_set(lt, idx);\n                    if ((ca > 0) != (cb > 0)) mask_set(sdiff, idx);\n                    if (abs(ca - cb) >= 2) mask_set(bigdiff, idx);\n                }\n                add_candidate_mask(cand, gt);\n                add_candidate_mask(cand, lt);\n                add_candidate_mask(cand, sdiff);\n                add_candidate_mask(cand, bigdiff);\n                add_candidate_mask(cand, mask_and(gt, checkerMask[0]));\n                add_candidate_mask(cand, mask_and(gt, checkerMask[1]));\n                add_candidate_mask(cand, mask_and(lt, checkerMask[0]));\n                add_candidate_mask(cand, mask_and(lt, checkerMask[1]));\n            }\n        }\n\n        return cand;\n    }\n\n    bool do_adaptive_query_round(int maxQueries, bool canAnswerAfter) {\n        for (int rep = 0; rep < maxQueries; rep++) {\n            if (Qcur >= MAXQ || elapsed() > 2.55) break;\n            if (!can_spend_ops(1)) break;\n\n            auto us = summarize_unions();\n            WeightedStates ws = collect_weighted_states();\n            if (ws.idx.empty()) break;\n\n            vector<Mask> cand = generate_candidate_masks(us, ws);\n            if (cand.empty()) break;\n\n            double bestScore = -1e100;\n            int bestId = -1;\n            for (int i = 0; i < (int)cand.size(); i++) {\n                double sc = evaluate_candidate_query(cand[i], ws);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestId = i;\n                }\n            }\n\n            double threshold = 0.12;\n            if (adaptiveQueriesUsed == 0) threshold = 0.30;\n            else if (adaptiveQueriesUsed < 4) threshold = 0.18;\n\n            if (bestId == -1 || bestScore < threshold) break;\n            if (!add_adaptive_query(cand[bestId])) break;\n\n            optimize_pool(4, 8, 3, false);\n            if (!pool.empty() && collect_weighted_states().bestPen > 0 && elapsed() < 2.25) {\n                optimize_pool(5, 10, 4, false);\n            }\n\n            if (canAnswerAfter) {\n                if (try_answer_strong(0.992, false)) return true;\n                if (try_small_ambiguous_finish(12)) return true;\n            }\n        }\n        return false;\n    }\n\n    bool adaptive_refine_loop(int rounds, bool canAnswerAfter) {\n        for (int t = 0; t < rounds; t++) {\n            if (elapsed() > 2.60) break;\n            int before = adaptiveQueriesUsed;\n            if (do_adaptive_query_round(1, canAnswerAfter)) return true;\n            if (adaptiveQueriesUsed == before) break;\n\n            auto us = summarize_unions();\n            if (us.hasPlausible) {\n                if (try_answer_strong(0.997, true)) return true;\n                if (us.bestWeight > 0.985 && us.maxCellScore < 0.02) {\n                    if (try_answer_strong(0.98, true)) return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    // ---------- main ----------\n    void solve() {\n        stTime = chrono::steady_clock::now();\n\n        read_input();\n        build_queries();\n        precompute_placements();\n\n        bool hard = (M >= 9 || compLog2 > 78.0 || eps >= 0.14);\n\n        // Stage 1: rows + cols\n        activate_queries(0, 2 * N);\n        optimize_pool(14, 0, 6, true);\n\n        if (try_answer_strong(0.999, false)) return;\n        if (try_small_ambiguous_finish(10)) return;\n        if (M <= 8 && exact_beam_merge()) {\n            if (try_answer_strong(0.998, false)) return;\n            if (try_small_ambiguous_finish(10)) return;\n        }\n        if (adaptive_refine_loop(hard ? 6 : 4, true)) return;\n\n        // Stage 2: mod2\n        activate_queries(2 * N, 2 * N + 4);\n        optimize_pool(8, 8, 5, false);\n\n        if (M <= 9 && exact_beam_merge()) {\n            if (try_answer_strong(0.997, false)) return;\n            if (try_small_ambiguous_finish(12)) return;\n        }\n        if (try_answer_strong(0.997, false)) return;\n        if (try_small_ambiguous_finish(12)) return;\n        if (adaptive_refine_loop(hard ? 6 : 4, true)) return;\n\n        // Stage 3: mod3 almost always worth asking\n        auto us = summarize_unions();\n        bool doMod3 = true;\n        if (hard && adaptiveQueriesUsed >= 10 && us.bestWeight < 0.12) doMod3 = false;\n\n        if (doMod3) {\n            activate_queries(2 * N + 4, 2 * N + 13);\n            optimize_pool(8, 10, 5, false);\n\n            if (M <= 9 && exact_beam_merge()) {\n                if (try_answer_strong(0.994, false)) return;\n                if (try_small_ambiguous_finish(16)) return;\n            }\n            if (try_answer_strong(0.992, false)) return;\n            if (try_small_ambiguous_finish(16)) return;\n            if (try_dual_guess(0.88, 10)) return;\n            if (adaptive_refine_loop(hard ? 5 : 4, true)) return;\n        }\n\n        int heuristicLimit;\n        if (hard) heuristicLimit = 7;\n        else if (M <= 4) heuristicLimit = 18;\n        else if (M <= 8) heuristicLimit = 12;\n        else heuristicLimit = 9;\n\n        for (int step = 0; step < heuristicLimit; step++) {\n            if (elapsed() > 2.62) break;\n\n            auto cur = summarize_unions();\n\n            double wth = 0.97;\n            if ((int)drilledCells.size() >= 2) wth = 0.95;\n            if ((int)drilledCells.size() >= 4) wth = 0.92;\n\n            if (try_answer_strong(wth, true)) return;\n            if (step >= 2 && try_dual_guess(0.90, 10)) return;\n\n            int ambLimit = min(26, 8 + 2 * step);\n            if (try_small_ambiguous_finish(ambLimit)) return;\n\n            if (adaptiveQueriesUsed < 18 && elapsed() < 2.48) {\n                int before = adaptiveQueriesUsed;\n                if (adaptive_refine_loop(step < 2 ? 2 : 1, true)) return;\n                cur = summarize_unions();\n                if (adaptiveQueriesUsed > before) {\n                    if (try_answer_strong(wth, true)) return;\n                    if (try_small_ambiguous_finish(ambLimit)) return;\n                }\n            }\n\n            if (M <= 8 && step <= 2 && elapsed() < 2.30) {\n                if (exact_beam_merge()) {\n                    if (try_answer_strong(wth, true)) return;\n                    if (try_small_ambiguous_finish(ambLimit)) return;\n                }\n            }\n\n            int idx = cur.bestCell;\n            if (idx < 0) break;\n            if (ops + 2 > maxOps) break;\n\n            int val = ask_drill(idx);\n            record_drill(idx, val);\n\n            if (elapsed() < 2.5) {\n                optimize_pool(5, 10, 4, false);\n                if (!pool.empty() && collect_weighted_states().bestPen > 0 && elapsed() < 2.25) {\n                    optimize_pool(6, 12, 5, false);\n                }\n            }\n        }\n\n        // Last cheap attempts\n        if (adaptiveQueriesUsed < 22 && elapsed() < 2.55) {\n            if (adaptive_refine_loop(2, true)) return;\n        }\n        if (M <= 8 && elapsed() < 2.50) {\n            if (exact_beam_merge()) {\n                if (try_answer_strong(0.92, true)) return;\n            }\n        }\n        if (try_dual_guess(0.80, 8)) return;\n        if (try_small_ambiguous_finish(24)) return;\n        if (try_answer_strong(0.90, true)) return;\n        if (speculative_guess()) return;\n        if (try_one_last_best_guess()) return;\n\n        full_drill_and_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long INF64 = (1LL << 60);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct Solution {\n    long long cost = INF64;\n    vector<vector<Rect>> rects; // [D][N]\n};\n\nstruct CutList {\n    int len = 0;\n    int v[50];\n};\n\nstruct DayRowLayout {\n    short l = 0, r = 0;      // [l, r)\n    unsigned char rev = 0;   // 0: forward, 1: reverse\n    short slack_idx = 0;     // which reservation absorbs row slack\n    CutList cuts;\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 D, N;\nvector<vector<int>> a;\n\n// prefW[h][d][k] flattened = sum_{t<k} ceil(a[d][t] / h)\nvector<int> prefW;\nint strideK, strideD;\n\ninline int pref_idx(int h, int d, int k) {\n    return h * strideD + d * strideK + k;\n}\ninline int sum_widths(int h, int d, int l, int r) {\n    return prefW[pref_idx(h, d, r)] - prefW[pref_idx(h, d, l)];\n}\ninline int cell_width(int h, int d, int k) {\n    return prefW[pref_idx(h, d, k + 1)] - prefW[pref_idx(h, d, k)];\n}\n\ninline int count_common_arr(const int* A, int nA, const int* B, int nB) {\n    int i = 0, j = 0, c = 0;\n    while (i < nA && j < nB) {\n        if (A[i] == B[j]) {\n            ++c; ++i; ++j;\n        } else if (A[i] < B[j]) {\n            ++i;\n        } else {\n            ++j;\n        }\n    }\n    return c;\n}\ninline long long dist_cut_arr(const CutList& A, const int* B, int lenB, int h) {\n    int common = count_common_arr(A.v, A.len, B, lenB);\n    return 1LL * h * (A.len + lenB - 2LL * common);\n}\n\n// ---------- Exact evaluator ----------\n\nlong long evaluate_exact(const vector<vector<Rect>>& rects) {\n    const int HS = (W - 1) * W;\n    const int VS = W * (W - 1);\n    const int HWORDS = (HS + 63) >> 6;\n    const int VWORDS = (VS + 63) >> 6;\n\n    vector<uint64_t> prevH(HWORDS, 0), prevV(VWORDS, 0);\n    vector<uint64_t> curH(HWORDS, 0), curV(VWORDS, 0);\n\n    auto setbit = [](vector<uint64_t>& bits, int idx) {\n        bits[idx >> 6] |= (1ULL << (idx & 63));\n    };\n\n    long long cost = 0;\n\n    for (int d = 0; d < D; ++d) {\n        fill(curH.begin(), curH.end(), 0);\n        fill(curV.begin(), curV.end(), 0);\n\n        for (int k = 0; k < N; ++k) {\n            const auto& r = rects[d][k];\n            long long area = 1LL * (r.i1 - r.i0) * (r.j1 - r.j0);\n            if (area < a[d][k]) cost += 100LL * (a[d][k] - area);\n\n            if (r.i0 > 0) {\n                int base = (r.i0 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.i1 < W) {\n                int base = (r.i1 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.j0 > 0) {\n                int x = r.j0 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n            if (r.j1 < W) {\n                int x = r.j1 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n        }\n\n        if (d > 0) {\n            for (int i = 0; i < HWORDS; ++i) cost += __builtin_popcountll(prevH[i] ^ curH[i]);\n            for (int i = 0; i < VWORDS; ++i) cost += __builtin_popcountll(prevV[i] ^ curV[i]);\n        }\n\n        prevH.swap(curH);\n        prevV.swap(curV);\n    }\n\n    return cost;\n}\n\n// ---------- Candidate 1: fixed full-width strips ----------\n\nlong long marginal_gain_all_days(int idx, int cur_h) {\n    long long gain = 0;\n    int area = W * cur_h;\n    for (int d = 0; d < D; ++d) {\n        int rem = a[d][idx] - area;\n        if (rem > 0) gain += 100LL * min(W, rem);\n    }\n    return gain;\n}\n\nvector<int> optimize_fixed_strips_all_days() {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>;\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_all_days(i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_all_days(idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_fixed_strips() {\n    Solution sol;\n    vector<int> h = optimize_fixed_strips_all_days();\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Candidate 2: day-by-day strips ----------\n\nlong long marginal_gain_one_day(int d, int idx, int cur_h) {\n    int area = W * cur_h;\n    int rem = a[d][idx] - area;\n    if (rem <= 0) return 0;\n    return 100LL * min(W, rem);\n}\n\nvector<int> optimize_strips_one_day(int d) {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>;\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_one_day(d, i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_one_day(d, idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_daily_strips() {\n    Solution sol;\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        vector<int> h = optimize_strips_one_day(d);\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Pattern generation helpers ----------\n\nvector<int> solve_reqH_dp(const vector<vector<int>>& reqH) {\n    vector<int> dpH(N + 1, W + 1), dpRows(N + 1, (int)1e9), parent(N + 1, -1);\n    dpH[0] = 0;\n    dpRows[0] = 0;\n\n    for (int r = 1; r <= N; ++r) {\n        for (int l = 0; l < r; ++l) {\n            int h = reqH[l][r];\n            if (h > W || dpH[l] > W) continue;\n            int nh = dpH[l] + h;\n            int nr = dpRows[l] + 1;\n            if (nh < dpH[r] || (nh == dpH[r] && nr < dpRows[r])) {\n                dpH[r] = nh;\n                dpRows[r] = nr;\n                parent[r] = l;\n            }\n        }\n    }\n\n    if (dpH[N] > W) return {};\n\n    vector<int> hs;\n    int cur = N;\n    while (cur > 0) {\n        int l = parent[cur];\n        hs.push_back(reqH[l][cur]);\n        cur = l;\n    }\n    reverse(hs.begin(), hs.end());\n    return hs;\n}\n\nvector<int> compute_global_pattern_all_days() {\n    auto interval_ok = [&](int l, int r, int h) -> bool {\n        for (int d = 0; d < D; ++d) {\n            if (sum_widths(h, d, l, r) > W) return false;\n        }\n        return true;\n    };\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            if (!interval_ok(l, r, W)) continue;\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (interval_ok(l, r, mid)) hi = mid;\n                else lo = mid + 1;\n            }\n            reqH[l][r] = lo;\n        }\n    }\n    return solve_reqH_dp(reqH);\n}\n\nvector<int> compute_pattern_from_values(vector<int> vec) {\n    for (int k = 1; k < N; ++k) vec[k] = max(vec[k], vec[k - 1]);\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            long long needW = 0;\n            for (int k = l; k < r; ++k) needW += (vec[k] + W - 1) / W;\n            if (needW > W) continue;\n\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                long long need = 0;\n                for (int k = l; k < r; ++k) need += (vec[k] + mid - 1) / mid;\n                if (need <= W) hi = mid;\n                else lo = mid + 1;\n            }\n            reqH[l][r] = lo;\n        }\n    }\n    return solve_reqH_dp(reqH);\n}\n\nvector<int> quantile_vector(double q) {\n    vector<int> v(N);\n    vector<int> tmp(D);\n    for (int k = 0; k < N; ++k) {\n        for (int d = 0; d < D; ++d) tmp[d] = a[d][k];\n        sort(tmp.begin(), tmp.end());\n        int idx = min(D - 1, max(0, (int)floor(q * (D - 1) + 1e-9)));\n        v[k] = tmp[idx];\n    }\n    for (int k = 1; k < N; ++k) v[k] = max(v[k], v[k - 1]);\n    return v;\n}\n\nvector<int> scaled_max_vector() {\n    vector<int> mx(N, 0);\n    for (int k = 0; k < N; ++k) {\n        for (int d = 0; d < D; ++d) mx[k] = max(mx[k], a[d][k]);\n    }\n    for (int k = 1; k < N; ++k) mx[k] = max(mx[k], mx[k - 1]);\n\n    long long sum = 0;\n    for (int x : mx) sum += x;\n    if (sum <= 1000000LL) return mx;\n\n    double scale = 1000000.0 / (double)sum;\n    vector<int> v(N);\n    for (int k = 0; k < N; ++k) v[k] = max(1, (int)floor(mx[k] * scale));\n    for (int k = 1; k < N; ++k) v[k] = max(v[k], v[k - 1]);\n    return v;\n}\n\nvector<int> make_equal_heights(int R) {\n    vector<int> hs(R, W / R);\n    int rem = W % R;\n    for (int i = 0; i < rem; ++i) hs[R - 1 - i]++;\n    return hs;\n}\n\nvector<int> stretch_pattern_proportional(const vector<int>& hs) {\n    if (hs.empty()) return {};\n    int S = 0;\n    for (int x : hs) S += x;\n    if (S <= 0 || S > W) return {};\n    if (S == W) return hs;\n\n    int m = (int)hs.size();\n    vector<int> out(m);\n    vector<pair<double, int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; ++i) {\n        double raw = (double)hs[i] * W / (double)S;\n        int v = max(1, (int)floor(raw));\n        out[i] = v;\n        used += v;\n        frac.push_back({raw - v, i});\n    }\n    sort(frac.begin(), frac.end(), [&](auto& a, auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    int p = 0;\n    while (used < W) {\n        out[frac[p].second]++;\n        ++used;\n        ++p;\n        if (p == m) p = 0;\n    }\n    while (used > W) {\n        bool ok = false;\n        for (int i = m - 1; i >= 0; --i) {\n            int id = frac[i].second;\n            if (out[id] > 1) {\n                out[id]--;\n                --used;\n                ok = true;\n                if (used == W) break;\n            }\n        }\n        if (!ok) break;\n    }\n    return out;\n}\n\nvector<int> stretch_pattern_tail(const vector<int>& hs) {\n    if (hs.empty()) return {};\n    vector<int> out = hs;\n    int S = 0;\n    for (int x : out) S += x;\n    if (S <= 0 || S > W) return {};\n    if (S < W) out.back() += (W - S);\n    return out;\n}\n\nvector<int> stretch_pattern_head(const vector<int>& hs) {\n    if (hs.empty()) return {};\n    vector<int> out = hs;\n    int S = 0;\n    for (int x : out) S += x;\n    if (S <= 0 || S > W) return {};\n    if (S < W) out.front() += (W - S);\n    return out;\n}\n\nvector<int> stretch_pattern_index_weighted(const vector<int>& hs) {\n    if (hs.empty()) return {};\n    vector<int> out = hs;\n    int S = 0;\n    for (int x : out) S += x;\n    if (S <= 0 || S > W) return {};\n    int rem = W - S;\n    if (rem <= 0) return out;\n\n    int m = (int)out.size();\n    long long wsum = 1LL * m * (m + 1) / 2;\n    vector<pair<double, int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; ++i) {\n        double raw = (double)rem * (i + 1) / (double)wsum;\n        int add = (int)floor(raw);\n        out[i] += add;\n        used += add;\n        frac.push_back({raw - add, i});\n    }\n    sort(frac.begin(), frac.end(), [&](auto& a, auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second > b.second;\n    });\n    int p = 0;\n    while (used < rem) {\n        out[frac[p].second]++;\n        ++used;\n        ++p;\n        if (p == m) p = 0;\n    }\n    return out;\n}\n\n// ---------- Candidate 3: fixed intervals across all days ----------\n\nstruct RowChoice {\n    int l, r;\n    int h;\n    int last_idx;\n    bool rev;\n};\n\nstruct RowDPResult {\n    Solution sol;\n    vector<int> heights;\n    bool feasible = false;\n};\n\nRowDPResult solve_row_dp_zero_shortage_fixed_intervals(const Timer& timer, double limit_sec) {\n    RowDPResult res;\n    res.sol.cost = INF64;\n\n    auto interval_ok = [&](int l, int r, int h) -> bool {\n        for (int d = 0; d < D; ++d) {\n            if (sum_widths(h, d, l, r) > W) return false;\n        }\n        return true;\n    };\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    vector<vector<long long>> rowCost(N + 1, vector<long long>(N + 1, INF64));\n    vector<vector<int>> bestLast(N + 1, vector<int>(N + 1, -1));\n    vector<vector<char>> bestRev(N + 1, vector<char>(N + 1, 0));\n\n    for (int l = 0; l < N; ++l) {\n        if (timer.elapsed() > limit_sec - 0.80) return res;\n        for (int r = l + 1; r <= N; ++r) {\n            if (!interval_ok(l, r, W)) continue;\n\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (interval_ok(l, r, mid)) hi = mid;\n                else lo = mid + 1;\n            }\n            int h = lo;\n            reqH[l][r] = h;\n\n            int m = r - l;\n            if (m == 1) {\n                rowCost[l][r] = 0;\n                bestLast[l][r] = l;\n                bestRev[l][r] = 0;\n                continue;\n            }\n\n            long long bestC = INF64;\n            int bestP = l;\n            bool bestR = false;\n\n            int prevCuts[55], curCuts[55];\n            for (int p = l; p < r; ++p) {\n                for (int rev = 0; rev <= 1; ++rev) {\n                    long long total = 0;\n                    int prevLen = 0;\n\n                    for (int d = 0; d < D; ++d) {\n                        int len = 0, s = 0;\n                        if (!rev) {\n                            for (int k = l; k < r; ++k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        } else {\n                            for (int k = r - 1; k >= l; --k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        }\n\n                        if (d > 0) {\n                            int common = count_common_arr(prevCuts, prevLen, curCuts, len);\n                            total += 2LL * h * (len - common);\n                        }\n                        prevLen = len;\n                        for (int i = 0; i < len; ++i) prevCuts[i] = curCuts[i];\n                    }\n\n                    if (total < bestC) {\n                        bestC = total;\n                        bestP = p;\n                        bestR = (bool)rev;\n                    }\n                }\n            }\n\n            rowCost[l][r] = bestC;\n            bestLast[l][r] = bestP;\n            bestRev[l][r] = (char)bestR;\n        }\n    }\n\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, INF64));\n    vector<vector<short>> prvI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> prvH(N + 1, vector<short>(W + 1, -1));\n    dp[0][0] = 0;\n\n    for (int i = 0; i < N; ++i) {\n        if (timer.elapsed() > limit_sec - 0.60) return res;\n        for (int used = 0; used <= W; ++used) {\n            if (dp[i][used] >= INF64) continue;\n            for (int j = i + 1; j <= N; ++j) {\n                int h = reqH[i][j];\n                if (h > W || used + h > W) continue;\n                long long nd = dp[i][used] + rowCost[i][j];\n                if (nd < dp[j][used + h]) {\n                    dp[j][used + h] = nd;\n                    prvI[j][used + h] = (short)i;\n                    prvH[j][used + h] = (short)used;\n                }\n            }\n        }\n    }\n\n    int bestUsed = -1;\n    long long bestVal = INF64;\n    for (int used = 0; used <= W; ++used) {\n        if (dp[N][used] < bestVal) {\n            bestVal = dp[N][used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0 || bestVal >= INF64) return res;\n\n    vector<RowChoice> rows;\n    {\n        int ci = N, ch = bestUsed;\n        while (ci > 0) {\n            int pi = prvI[ci][ch];\n            int ph = prvH[ci][ch];\n            RowChoice rc;\n            rc.l = pi;\n            rc.r = ci;\n            rc.h = reqH[pi][ci];\n            rc.last_idx = bestLast[pi][ci];\n            rc.rev = bestRev[pi][ci];\n            rows.push_back(rc);\n            ci = pi;\n            ch = ph;\n        }\n        reverse(rows.begin(), rows.end());\n    }\n\n    res.heights.clear();\n    for (auto& rc : rows) res.heights.push_back(rc.h);\n\n    res.sol.rects.assign(D, vector<Rect>(N));\n    int y = 0;\n    for (const auto& row : rows) {\n        int l = row.l, r = row.r, h = row.h, p = row.last_idx;\n        bool rev = row.rev;\n\n        for (int d = 0; d < D; ++d) {\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r; ++k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            } else {\n                for (int k = r - 1; k >= l; --k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            }\n            res.sol.rects[d][p] = {y, x, y + h, W};\n        }\n        y += h;\n    }\n\n    if (timer.elapsed() > limit_sec - 0.30) return res;\n\n    res.sol.cost = evaluate_exact(res.sol.rects);\n    res.feasible = true;\n    return res;\n}\n\n// ---------- Candidate 4: fixed row heights, variable daily intervals ----------\n\nstatic long long intervalCost[55][55][55];\nstatic unsigned char intervalRev[55][55][55];\nstatic short intervalSlack[55][55][55];\nstatic long long dpDay[55][55];\nstatic short parL[55][55];\nstatic unsigned char parRev[55][55];\nstatic short parSlack[55][55];\n\ninline void build_cuts_with_slack(int h, int d, int l, int r, bool rev, int slack_idx, CutList& out) {\n    int slack = W - sum_widths(h, d, l, r);\n    out.len = max(0, r - l - 1);\n\n    int x = 0, p = 0;\n    if (!rev) {\n        for (int k = l; k < r - 1; ++k) {\n            x += cell_width(h, d, k);\n            if (k == slack_idx) x += slack;\n            out.v[p++] = x;\n        }\n    } else {\n        for (int k = r - 1; k > l; --k) {\n            x += cell_width(h, d, k);\n            if (k == slack_idx) x += slack;\n            out.v[p++] = x;\n        }\n    }\n}\n\nbool optimize_one_day_for_pattern(\n    int d,\n    const vector<int>& hs,\n    const vector<DayRowLayout>* prevDay,\n    const vector<DayRowLayout>* nextDay,\n    bool useProxy,\n    bool richSlack,\n    vector<DayRowLayout>& out\n) {\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return false;\n\n    int cuts[50];\n\n    for (int row = 0; row < R; ++row) {\n        int h = hs[row];\n        const CutList* pc = prevDay ? &((*prevDay)[row].cuts) : nullptr;\n        const CutList* nc = nextDay ? &((*nextDay)[row].cuts) : nullptr;\n\n        for (int l = 0; l <= N; ++l) {\n            for (int r = 0; r <= N; ++r) {\n                intervalCost[row][l][r] = INF64;\n                intervalRev[row][l][r] = 0;\n                intervalSlack[row][l][r] = 0;\n            }\n        }\n\n        for (int l = 0; l < N; ++l) {\n            for (int r = l + 1; r <= N; ++r) {\n                int minW = sum_widths(h, d, l, r);\n                if (minW > W) continue;\n                int len = r - l - 1;\n\n                if (!pc && !nc && useProxy) {\n                    // Proxy cost does not distinguish slack position;\n                    // use the cheap natural candidate.\n                    intervalCost[row][l][r] = 1LL * h * len;\n                    intervalRev[row][l][r] = 0;\n                    intervalSlack[row][l][r] = (short)(r - 1);\n                    continue;\n                }\n\n                int candPos[3];\n                int candCnt = 0;\n                candPos[candCnt++] = l;\n                int mid = (l + r - 1) >> 1;\n                bool existsMid = false;\n                for (int i = 0; i < candCnt; ++i) if (candPos[i] == mid) existsMid = true;\n                if (!existsMid) candPos[candCnt++] = mid;\n                bool existsLast = false;\n                for (int i = 0; i < candCnt; ++i) if (candPos[i] == r - 1) existsLast = true;\n                if (!existsLast) candPos[candCnt++] = r - 1;\n\n                for (int rev = 0; rev <= 1; ++rev) {\n                    if (!richSlack) {\n                        int slack_idx = (rev ? l : r - 1);\n                        int x = 0, p = 0;\n                        if (!rev) {\n                            for (int k = l; k < r - 1; ++k) {\n                                x += cell_width(h, d, k);\n                                cuts[p++] = x;\n                            }\n                        } else {\n                            for (int k = r - 1; k > l; --k) {\n                                x += cell_width(h, d, k);\n                                cuts[p++] = x;\n                            }\n                        }\n\n                        long long c = 0;\n                        if (pc) c += dist_cut_arr(*pc, cuts, len, h);\n                        if (nc) c += dist_cut_arr(*nc, cuts, len, h);\n\n                        if (c < intervalCost[row][l][r]) {\n                            intervalCost[row][l][r] = c;\n                            intervalRev[row][l][r] = (unsigned char)rev;\n                            intervalSlack[row][l][r] = (short)slack_idx;\n                        }\n                    } else {\n                        for (int ci = 0; ci < candCnt; ++ci) {\n                            int slack_idx = candPos[ci];\n                            int slack = W - minW;\n\n                            int x = 0, p = 0;\n                            if (!rev) {\n                                for (int k = l; k < r - 1; ++k) {\n                                    x += cell_width(h, d, k);\n                                    if (k == slack_idx) x += slack;\n                                    cuts[p++] = x;\n                                }\n                            } else {\n                                for (int k = r - 1; k > l; --k) {\n                                    x += cell_width(h, d, k);\n                                    if (k == slack_idx) x += slack;\n                                    cuts[p++] = x;\n                                }\n                            }\n\n                            long long c = 0;\n                            if (pc) c += dist_cut_arr(*pc, cuts, len, h);\n                            if (nc) c += dist_cut_arr(*nc, cuts, len, h);\n\n                            if (c < intervalCost[row][l][r]) {\n                                intervalCost[row][l][r] = c;\n                                intervalRev[row][l][r] = (unsigned char)rev;\n                                intervalSlack[row][l][r] = (short)slack_idx;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    for (int i = 0; i <= R; ++i) {\n        for (int j = 0; j <= N; ++j) {\n            dpDay[i][j] = INF64;\n            parL[i][j] = -1;\n            parRev[i][j] = 0;\n            parSlack[i][j] = 0;\n        }\n    }\n    dpDay[0][0] = 0;\n\n    for (int row = 0; row < R; ++row) {\n        for (int l = 0; l <= N; ++l) {\n            if (dpDay[row][l] >= INF64) continue;\n            int minR = l + 1;\n            int maxR = N - (R - row - 1);\n            for (int r = minR; r <= maxR; ++r) {\n                long long c = intervalCost[row][l][r];\n                if (c >= INF64) continue;\n                long long nd = dpDay[row][l] + c;\n                if (nd < dpDay[row + 1][r]) {\n                    dpDay[row + 1][r] = nd;\n                    parL[row + 1][r] = (short)l;\n                    parRev[row + 1][r] = intervalRev[row][l][r];\n                    parSlack[row + 1][r] = intervalSlack[row][l][r];\n                }\n            }\n        }\n    }\n\n    if (dpDay[R][N] >= INF64) return false;\n\n    out.assign(R, DayRowLayout{});\n    int cur = N;\n    for (int row = R; row >= 1; --row) {\n        int l = parL[row][cur];\n        bool rev = parRev[row][cur];\n        int slack_idx = parSlack[row][cur];\n\n        out[row - 1].l = (short)l;\n        out[row - 1].r = (short)cur;\n        out[row - 1].rev = (unsigned char)rev;\n        out[row - 1].slack_idx = (short)slack_idx;\n        build_cuts_with_slack(hs[row - 1], d, l, cur, rev, slack_idx, out[row - 1].cuts);\n        cur = l;\n    }\n\n    return true;\n}\n\nSolution solve_fixed_height_pattern(\n    const vector<int>& hs,\n    const Timer& timer,\n    double limit_sec,\n    int extra_sweeps,\n    bool richSlack\n) {\n    Solution sol;\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return sol;\n\n    int sumH = 0;\n    for (int h : hs) {\n        if (h <= 0) return sol;\n        sumH += h;\n    }\n    if (sumH > W) return sol;\n\n    vector<vector<DayRowLayout>> lay(D, vector<DayRowLayout>(R));\n\n    if (timer.elapsed() > limit_sec - 0.25) return sol;\n\n    if (!optimize_one_day_for_pattern(0, hs, nullptr, nullptr, true, richSlack, lay[0])) return sol;\n    for (int d = 1; d < D; ++d) {\n        if (timer.elapsed() > limit_sec - 0.25) return sol;\n        if (!optimize_one_day_for_pattern(d, hs, &lay[d - 1], nullptr, false, richSlack, lay[d])) return sol;\n    }\n\n    for (int d = D - 2; d >= 0; --d) {\n        if (timer.elapsed() > limit_sec - 0.25) return sol;\n        const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n        if (!optimize_one_day_for_pattern(d, hs, prevDay, &lay[d + 1], false, richSlack, lay[d])) return sol;\n    }\n\n    for (int it = 0; it < extra_sweeps; ++it) {\n        if (timer.elapsed() > limit_sec - 0.50) break;\n        for (int d = 0; d < D; ++d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, richSlack, lay[d])) return sol;\n        }\n        for (int d = D - 1; d >= 0; --d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, richSlack, lay[d])) return sol;\n        }\n    }\n\n    if (timer.elapsed() > limit_sec - 0.18) return sol;\n\n    sol.rects.assign(D, vector<Rect>(N));\n    vector<int> y0(R + 1, 0);\n    for (int r = 0; r < R; ++r) y0[r + 1] = y0[r] + hs[r];\n\n    for (int d = 0; d < D; ++d) {\n        for (int row = 0; row < R; ++row) {\n            int y = y0[row];\n            int h = hs[row];\n            int l = lay[d][row].l;\n            int r = lay[d][row].r;\n            bool rev = lay[d][row].rev;\n            int slack_idx = lay[d][row].slack_idx;\n            int slack = W - sum_widths(h, d, l, r);\n\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r; ++k) {\n                    int w = cell_width(h, d, k);\n                    if (k == slack_idx) w += slack;\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            } else {\n                for (int k = r - 1; k >= l; --k) {\n                    int w = cell_width(h, d, k);\n                    if (k == slack_idx) w += slack;\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            }\n        }\n    }\n\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Main ----------\n\nvoid consider_best(Solution& best, Solution cand) {\n    if (cand.cost < best.cost) best = std::move(cand);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double LIMIT_SEC = 2.80;\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    strideK = N + 1;\n    strideD = D * strideK;\n    prefW.assign((W + 1) * strideD, 0);\n\n    for (int h = 1; h <= W; ++h) {\n        for (int d = 0; d < D; ++d) {\n            prefW[pref_idx(h, d, 0)] = 0;\n            for (int k = 0; k < N; ++k) {\n                prefW[pref_idx(h, d, k + 1)] =\n                    prefW[pref_idx(h, d, k)] + (a[d][k] + h - 1) / h;\n            }\n        }\n    }\n\n    Solution best = solve_fixed_strips();\n    if (timer.elapsed() < LIMIT_SEC - 1.00) {\n        consider_best(best, solve_daily_strips());\n    }\n\n    RowDPResult rowdp = solve_row_dp_zero_shortage_fixed_intervals(timer, LIMIT_SEC);\n    if (rowdp.feasible) consider_best(best, rowdp.sol);\n\n    vector<vector<int>> patterns;\n    set<vector<int>> seen;\n\n    auto add_pattern = [&](vector<int> hs, bool add_sorted_variant = false) {\n        if (hs.empty()) return;\n        int sumH = 0;\n        for (int h : hs) {\n            if (h <= 0) return;\n            sumH += h;\n        }\n        if (sumH > W) return;\n        if ((int)hs.size() > N) return;\n        if (seen.insert(hs).second) patterns.push_back(hs);\n        if (add_sorted_variant) {\n            vector<int> t = hs;\n            sort(t.begin(), t.end());\n            if (seen.insert(t).second) patterns.push_back(t);\n        }\n    };\n\n    // rowdp-derived seeds\n    if (rowdp.feasible) {\n        add_pattern(rowdp.heights, true);\n        add_pattern(stretch_pattern_proportional(rowdp.heights), true);\n        add_pattern(stretch_pattern_tail(rowdp.heights), true);\n        add_pattern(stretch_pattern_head(rowdp.heights), false);\n        add_pattern(stretch_pattern_index_weighted(rowdp.heights), true);\n    }\n\n    // global seed\n    if (timer.elapsed() < LIMIT_SEC - 1.35) {\n        auto globalPattern = compute_global_pattern_all_days();\n        add_pattern(globalPattern, true);\n        add_pattern(stretch_pattern_proportional(globalPattern), true);\n        add_pattern(stretch_pattern_tail(globalPattern), true);\n        add_pattern(stretch_pattern_head(globalPattern), false);\n        add_pattern(stretch_pattern_index_weighted(globalPattern), true);\n    }\n\n    // representative / conservative seeds\n    if (timer.elapsed() < LIMIT_SEC - 1.15) {\n        int bestDay = 0;\n        long long bestSum = -1;\n        for (int d = 0; d < D; ++d) {\n            long long s = 0;\n            for (int k = 0; k < N; ++k) s += a[d][k];\n            if (s > bestSum) {\n                bestSum = s;\n                bestDay = d;\n            }\n        }\n\n        auto bestDayPattern = compute_pattern_from_values(a[bestDay]);\n        add_pattern(bestDayPattern, true);\n        add_pattern(stretch_pattern_proportional(bestDayPattern), true);\n\n        vector<int> avgVec(N, 0);\n        for (int k = 0; k < N; ++k) {\n            long long s = 0;\n            for (int d = 0; d < D; ++d) s += a[d][k];\n            avgVec[k] = (int)((s + D / 2) / D);\n        }\n        add_pattern(compute_pattern_from_values(avgVec), true);\n\n        add_pattern(compute_pattern_from_values(quantile_vector(0.50)), false);\n        add_pattern(compute_pattern_from_values(quantile_vector(0.75)), true);\n        add_pattern(compute_pattern_from_values(quantile_vector(0.90)), false);\n        add_pattern(compute_pattern_from_values(scaled_max_vector()), true);\n    }\n\n    // equal-height backups\n    for (int R : {4, 5, 6, 3, 8, 2, 10, 1}) {\n        if (R <= N) add_pattern(make_equal_heights(R), false);\n    }\n\n    for (int idx = 0; idx < (int)patterns.size(); ++idx) {\n        if (timer.elapsed() > LIMIT_SEC - 0.22) break;\n\n        bool topPattern = (idx < 6);\n        int extra_sweeps = topPattern ? 1 : 0;\n\n        Solution cand = solve_fixed_height_pattern(\n            patterns[idx], timer, LIMIT_SEC, extra_sweeps, false\n        );\n        consider_best(best, std::move(cand));\n\n        // Richer slack-position search only for a few best patterns and only if time allows.\n        if (idx < 2 && timer.elapsed() < LIMIT_SEC - 0.90) {\n            Solution richCand = solve_fixed_height_pattern(\n                patterns[idx], timer, LIMIT_SEC, 0, true\n            );\n            consider_best(best, std::move(richCand));\n        }\n    }\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            const auto& r = best.rects[d][k];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nusing i64 = long long;\nusing u32 = uint32_t;\n\nstatic constexpr u32 MOD = 998244353;\nstatic constexpr int N = 9;\nstatic constexpr int M = 20;\nstatic constexpr int K = 81;\n\nstatic constexpr int REFINE_COMBO_MAX = 5;\n\n// Beam parameters\nstatic constexpr int BEAM_WIDTH_PER_USED = 3;\nstatic constexpr int TOP_SINGLE = 2;\nstatic constexpr int TOP_PAIR = 2;\nstatic constexpr int TOP_TRIPLE = 1;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 0) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nstruct Combo {\n    uint8_t cost = 0;\n    uint8_t ids[REFINE_COMBO_MAX]{};\n    u32 add[9]{};\n};\n\nstruct BeamNode {\n    u32 board[81]{};\n    i64 score = 0;\n    uint8_t used = 0;\n    int parent = -1;\n    int combo_id = 0;\n};\n\nstruct Solution {\n    u32 board[81]{};\n    i64 score = 0;\n    int used = 0;\n\n    int pos_cid[49]{};\n    u32 pos_add[49][9]{};\n    uint8_t pos_count[49]{};\n    uint8_t pos_ids[49][REFINE_COMBO_MAX]{};\n};\n\nclass Solver {\npublic:\n    Timer timer;\n    SplitMix64 rng;\n\n    u32 init_board[81]{};\n    i64 init_score = 0;\n    u32 stamp[20][9]{};\n    uint8_t pos_cells[49][9]{};\n\n    vector<Combo> combos;\n    array<vector<int>, REFINE_COMBO_MAX + 1> combo_ids_by_cost;\n    vector<int> all_positions;\n\n    void read_input() {\n        int n, m, k;\n        cin >> n >> m >> k;\n        (void)n; (void)m; (void)k;\n\n        uint64_t seed = 0x123456789abcdef0ULL;\n        auto mix = [&](uint64_t v) {\n            seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        };\n\n        for (int i = 0; i < 81; i++) {\n            cin >> init_board[i];\n            init_score += init_board[i];\n            mix(init_board[i] + 1000003ULL * (i + 1));\n        }\n        for (int m0 = 0; m0 < 20; m0++) {\n            for (int i = 0; i < 3; i++) {\n                for (int j = 0; j < 3; j++) {\n                    cin >> stamp[m0][i * 3 + j];\n                    mix(stamp[m0][i * 3 + j] + 10007ULL * (m0 + 1) + 131ULL * i + j);\n                }\n            }\n        }\n\n        rng = SplitMix64(seed);\n\n        build_pos_cells();\n        build_combos();\n\n        all_positions.resize(49);\n        iota(all_positions.begin(), all_positions.end(), 0);\n    }\n\n    void solve() {\n        const double TL = 1.94;\n\n        array<int, 49> row_order = make_row_major_order();\n        Solution best = build_by_beam(row_order);\n\n        // Try one more diverse beam order: positions with high initial local potential first.\n        if (timer.elapsed() < 0.22) {\n            array<int, 49> gain_order = make_gain_order();\n            Solution alt = build_by_beam(gain_order);\n            if (better(alt, best)) best = std::move(alt);\n        }\n\n        // A couple of cheap diversified starts.\n        if (timer.elapsed() < 0.32) {\n            for (int t = 0; t < 2 && timer.elapsed() < 0.42; t++) {\n                Solution alt = build_randomized_greedy();\n                refine_positions(alt, all_positions, min(0.62, TL), 1);\n                if (better(alt, best)) best = std::move(alt);\n            }\n        }\n\n        refine_positions(best, all_positions, 0.95, 3);\n\n        while (timer.elapsed() < 1.88) {\n            Solution cur = best;\n\n            int mode = rng.next_int(100);\n            vector<int> removed;\n            if (mode < 40) removed = random_destroy(cur);\n            else if (mode < 75) removed = weak_destroy(cur);\n            else removed = cluster_destroy(cur);\n\n            vector<int> focus = expand_focus_positions(removed);\n            double sub_limit = min(TL - 0.02, timer.elapsed() + 0.07 + 0.01 * (int)focus.size() / 10 + (mode >= 75 ? 0.02 : 0.0));\n\n            refine_positions(cur, focus, sub_limit, 2);\n\n            // If there is still time in this iteration, add one global polish round.\n            if (timer.elapsed() + 0.015 < sub_limit) {\n                refine_positions(cur, all_positions, sub_limit, 1);\n            }\n\n            if (better(cur, best)) best = std::move(cur);\n        }\n\n        refine_positions(best, all_positions, TL, 5);\n        output(best);\n    }\n\nprivate:\n    static inline i64 add_gain_cell(u32 x, u32 s) {\n        return (x + s >= MOD) ? (i64)s - MOD : (i64)s;\n    }\n\n    static inline i64 remove_gain_cell(u32 x, u32 s) {\n        return (x >= s) ? -(i64)s : (i64)MOD - s;\n    }\n\n    inline i64 gain_local(const u32 x[9], const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += add_gain_cell(x[k], add[k]);\n        return g;\n    }\n\n    inline void extract_local(const u32 board[81], int pos, u32 x[9]) const {\n        for (int k = 0; k < 9; k++) x[k] = board[pos_cells[pos][k]];\n    }\n\n    inline i64 gain_add_pos(const u32 board[81], int pos, const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += add_gain_cell(board[pos_cells[pos][k]], add[k]);\n        return g;\n    }\n\n    inline i64 gain_remove_pos(const u32 board[81], int pos, const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += remove_gain_cell(board[pos_cells[pos][k]], add[k]);\n        return g;\n    }\n\n    inline void apply_add_pos(u32 board[81], int pos, const u32 add[9]) const {\n        for (int k = 0; k < 9; k++) {\n            u32 &v = board[pos_cells[pos][k]];\n            v += add[k];\n            if (v >= MOD) v -= MOD;\n        }\n    }\n\n    inline void apply_remove_pos(u32 board[81], int pos, const u32 add[9]) const {\n        for (int k = 0; k < 9; k++) {\n            u32 &v = board[pos_cells[pos][k]];\n            u32 s = add[k];\n            if (v >= s) v -= s;\n            else v = v + MOD - s;\n        }\n    }\n\n    void build_pos_cells() {\n        for (int p = 0; p < 7; p++) {\n            for (int q = 0; q < 7; q++) {\n                int pos = p * 7 + q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        pos_cells[pos][t++] = (uint8_t)((p + i) * 9 + (q + j));\n                    }\n                }\n            }\n        }\n    }\n\n    void build_combos() {\n        combos.clear();\n        for (auto &v : combo_ids_by_cost) v.clear();\n        combos.reserve(60000);\n\n        Combo zero;\n        zero.cost = 0;\n        combos.push_back(zero);\n        combo_ids_by_cost[0].push_back(0);\n\n        u32 cur[9]{};\n        uint8_t ids[REFINE_COMBO_MAX]{};\n\n        function<void(int,int,int)> dfs = [&](int start, int depth, int target) {\n            if (depth == target) {\n                Combo c;\n                c.cost = (uint8_t)target;\n                for (int i = 0; i < target; i++) c.ids[i] = ids[i];\n                for (int k = 0; k < 9; k++) c.add[k] = cur[k];\n                int idx = (int)combos.size();\n                combos.push_back(c);\n                combo_ids_by_cost[target].push_back(idx);\n                return;\n            }\n            for (int m0 = start; m0 < 20; m0++) {\n                ids[depth] = (uint8_t)m0;\n                for (int k = 0; k < 9; k++) {\n                    u32 x = cur[k] + stamp[m0][k];\n                    if (x >= MOD) x -= MOD;\n                    cur[k] = x;\n                }\n                dfs(m0, depth + 1, target);\n                for (int k = 0; k < 9; k++) {\n                    u32 s = stamp[m0][k];\n                    if (cur[k] >= s) cur[k] -= s;\n                    else cur[k] = cur[k] + MOD - s;\n                }\n            }\n        };\n\n        for (int cost = 1; cost <= REFINE_COMBO_MAX; cost++) {\n            dfs(0, 0, cost);\n        }\n    }\n\n    Solution make_empty_solution() const {\n        Solution sol;\n        memcpy(sol.board, init_board, sizeof(init_board));\n        sol.score = init_score;\n        sol.used = 0;\n        for (int pos = 0; pos < 49; pos++) {\n            sol.pos_cid[pos] = 0;\n            sol.pos_count[pos] = 0;\n            for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = 0;\n            for (int t = 0; t < REFINE_COMBO_MAX; t++) sol.pos_ids[pos][t] = 0;\n        }\n        return sol;\n    }\n\n    void set_pos_meta(Solution &sol, int pos, int cid) const {\n        sol.pos_cid[pos] = cid;\n        const Combo &cb = combos[cid];\n        sol.pos_count[pos] = cb.cost;\n        for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = cb.add[k];\n        for (int t = 0; t < REFINE_COMBO_MAX; t++) {\n            sol.pos_ids[pos][t] = (t < cb.cost ? cb.ids[t] : 0);\n        }\n    }\n\n    void clear_pos_meta(Solution &sol, int pos) const {\n        sol.pos_cid[pos] = 0;\n        sol.pos_count[pos] = 0;\n        for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = 0;\n        for (int t = 0; t < REFINE_COMBO_MAX; t++) sol.pos_ids[pos][t] = 0;\n    }\n\n    void remove_position_combo(Solution &sol, int pos) const {\n        int cid = sol.pos_cid[pos];\n        if (cid == 0) return;\n        sol.score += gain_remove_pos(sol.board, pos, combos[cid].add);\n        apply_remove_pos(sol.board, pos, combos[cid].add);\n        sol.used -= combos[cid].cost;\n        clear_pos_meta(sol, pos);\n    }\n\n    bool better(const Solution &a, const Solution &b) const {\n        if (a.score != b.score) return a.score > b.score;\n        return a.used < b.used;\n    }\n\n    template<size_t SZ>\n    static inline void push_top(array<pair<i64,int>, SZ>& best, i64 gain, int cid) {\n        for (size_t i = 0; i < SZ; i++) {\n            if (gain > best[i].first) {\n                for (size_t j = SZ - 1; j > i; j--) best[j] = best[j - 1];\n                best[i] = {gain, cid};\n                return;\n            }\n        }\n    }\n\n    array<int, 49> make_row_major_order() const {\n        array<int, 49> ord{};\n        iota(ord.begin(), ord.end(), 0);\n        return ord;\n    }\n\n    array<int, 49> make_gain_order() const {\n        array<pair<i64,int>, 49> arr{};\n        for (int pos = 0; pos < 49; pos++) {\n            u32 x[9];\n            extract_local(init_board, pos, x);\n            i64 best = 0;\n            for (int c = 1; c <= 3; c++) {\n                for (int cid : combo_ids_by_cost[c]) {\n                    i64 g = gain_local(x, combos[cid].add);\n                    if (g > best) best = g;\n                }\n            }\n            arr[pos] = {best, pos};\n        }\n        sort(arr.begin(), arr.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        array<int, 49> ord{};\n        for (int i = 0; i < 49; i++) ord[i] = arr[i].second;\n        return ord;\n    }\n\n    Solution build_by_beam(const array<int, 49>& order) {\n        vector<vector<BeamNode>> layers(50);\n\n        BeamNode root;\n        memcpy(root.board, init_board, sizeof(init_board));\n        root.score = init_score;\n        root.used = 0;\n        root.parent = -1;\n        root.combo_id = 0;\n        layers[0].push_back(root);\n\n        array<vector<int>, K + 1> bucket_cur, bucket_nxt;\n        bucket_cur[0].push_back(0);\n\n        for (int step = 0; step < 49; step++) {\n            int pos = order[step];\n            array<vector<BeamNode>, K + 1> cand;\n            const auto &cur_layer = layers[step];\n\n            for (int used = 0; used <= K; used++) {\n                for (int idx : bucket_cur[used]) {\n                    const BeamNode &st = cur_layer[idx];\n\n                    u32 x[9];\n                    extract_local(st.board, pos, x);\n\n                    array<pair<i64,int>, TOP_SINGLE> best1;\n                    array<pair<i64,int>, TOP_PAIR> best2;\n                    array<pair<i64,int>, TOP_TRIPLE> best3;\n                    for (auto &p : best1) p = {-(1LL << 60), -1};\n                    for (auto &p : best2) p = {-(1LL << 60), -1};\n                    for (auto &p : best3) p = {-(1LL << 60), -1};\n\n                    if (used + 1 <= K) {\n                        for (int cid : combo_ids_by_cost[1]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best1, g, cid);\n                        }\n                    }\n                    if (used + 2 <= K) {\n                        for (int cid : combo_ids_by_cost[2]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best2, g, cid);\n                        }\n                    }\n                    if (used + 3 <= K) {\n                        for (int cid : combo_ids_by_cost[3]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best3, g, cid);\n                        }\n                    }\n\n                    auto make_child = [&](int cid) {\n                        const Combo &cb = combos[cid];\n                        BeamNode ch;\n                        memcpy(ch.board, st.board, sizeof(st.board));\n                        if (cid != 0) apply_add_pos(ch.board, pos, cb.add);\n                        ch.score = st.score + (cid == 0 ? 0 : gain_local(x, cb.add));\n                        ch.used = (uint8_t)(used + cb.cost);\n                        ch.parent = idx;\n                        ch.combo_id = cid;\n                        cand[ch.used].push_back(std::move(ch));\n                    };\n\n                    make_child(0);\n                    for (auto [g, cid] : best1) if (cid != -1) make_child(cid);\n                    for (auto [g, cid] : best2) if (cid != -1) make_child(cid);\n                    for (auto [g, cid] : best3) if (cid != -1) make_child(cid);\n                }\n            }\n\n            vector<BeamNode> next_layer;\n            for (auto &v : bucket_nxt) v.clear();\n\n            for (int used = 0; used <= K; used++) {\n                auto &vec = cand[used];\n                if (vec.empty()) continue;\n                sort(vec.begin(), vec.end(), [](const BeamNode &a, const BeamNode &b) {\n                    return a.score > b.score;\n                });\n                if ((int)vec.size() > BEAM_WIDTH_PER_USED) vec.resize(BEAM_WIDTH_PER_USED);\n                for (auto &node : vec) {\n                    bucket_nxt[used].push_back((int)next_layer.size());\n                    next_layer.push_back(std::move(node));\n                }\n            }\n\n            layers[step + 1] = std::move(next_layer);\n            bucket_cur = std::move(bucket_nxt);\n        }\n\n        int best_idx = 0;\n        i64 best_score = -(1LL << 60);\n        for (int i = 0; i < (int)layers[49].size(); i++) {\n            if (layers[49][i].score > best_score) {\n                best_score = layers[49][i].score;\n                best_idx = i;\n            }\n        }\n\n        int chosen_combo[49];\n        int cur = best_idx;\n        for (int step = 49; step >= 1; step--) {\n            chosen_combo[step - 1] = layers[step][cur].combo_id;\n            cur = layers[step][cur].parent;\n        }\n\n        Solution sol = make_empty_solution();\n        memcpy(sol.board, layers[49][best_idx].board, sizeof(sol.board));\n        sol.score = layers[49][best_idx].score;\n        sol.used = 0;\n\n        for (int step = 0; step < 49; step++) {\n            int pos = order[step];\n            int cid = chosen_combo[step];\n            set_pos_meta(sol, pos, cid);\n            sol.used += combos[cid].cost;\n        }\n        return sol;\n    }\n\n    Solution build_randomized_greedy() {\n        Solution sol = make_empty_solution();\n\n        vector<int> ord = all_positions;\n        for (int i = (int)ord.size() - 1; i > 0; i--) {\n            int j = rng.next_int(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        for (int pos : ord) {\n            int avail = K - sol.used;\n            int maxc = min(3, avail);\n            if (maxc <= 0) break;\n\n            array<pair<i64,int>, 6> best;\n            for (auto &p : best) p = {-(1LL << 60), -1};\n\n            u32 x[9];\n            extract_local(sol.board, pos, x);\n\n            for (int c = 1; c <= maxc; c++) {\n                for (int cid : combo_ids_by_cost[c]) {\n                    i64 g = gain_local(x, combos[cid].add);\n                    push_top(best, g, cid);\n                }\n            }\n\n            vector<pair<i64,int>> cand;\n            for (auto [g, cid] : best) {\n                if (cid != -1 && g > 0) cand.push_back({g, cid});\n            }\n            if (cand.empty()) continue;\n\n            int pick = 0;\n            int r = rng.next_int(100);\n            if ((int)cand.size() >= 2 && r >= 65) pick = 1;\n            if ((int)cand.size() >= 3 && r >= 90) pick = 2;\n\n            int cid = cand[pick].second;\n            sol.score += gain_add_pos(sol.board, pos, combos[cid].add);\n            apply_add_pos(sol.board, pos, combos[cid].add);\n            sol.used += combos[cid].cost;\n            set_pos_meta(sol, pos, cid);\n        }\n\n        return sol;\n    }\n\n    void shuffle_positions(vector<int>& ord) {\n        for (int i = (int)ord.size() - 1; i > 0; i--) {\n            int j = rng.next_int(i + 1);\n            swap(ord[i], ord[j]);\n        }\n    }\n\n    void refine_positions(Solution &sol, const vector<int>& base_positions, double time_limit, int max_rounds) {\n        if (base_positions.empty()) return;\n        vector<int> ord = base_positions;\n\n        for (int round = 0; round < max_rounds && timer.elapsed() < time_limit; round++) {\n            shuffle_positions(ord);\n            bool changed = false;\n\n            for (int pos : ord) {\n                if (timer.elapsed() >= time_limit) return;\n\n                int old_cid = sol.pos_cid[pos];\n                if (old_cid != 0) remove_position_combo(sol, pos);\n\n                u32 x[9];\n                extract_local(sol.board, pos, x);\n\n                int available = K - sol.used;\n                int maxc = min(REFINE_COMBO_MAX, available);\n\n                int best_cid = 0;\n                i64 best_delta = 0;\n                int best_cost = 0;\n\n                for (int c = 1; c <= maxc; c++) {\n                    for (int cid : combo_ids_by_cost[c]) {\n                        i64 d = gain_local(x, combos[cid].add);\n                        if (d > best_delta || (d == best_delta && c < best_cost)) {\n                            best_delta = d;\n                            best_cid = cid;\n                            best_cost = c;\n                        }\n                    }\n                }\n\n                if (best_cid != 0) {\n                    sol.score += gain_add_pos(sol.board, pos, combos[best_cid].add);\n                    apply_add_pos(sol.board, pos, combos[best_cid].add);\n                    sol.used += combos[best_cid].cost;\n                    set_pos_meta(sol, pos, best_cid);\n                } else {\n                    clear_pos_meta(sol, pos);\n                }\n\n                if (best_cid != old_cid) changed = true;\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> random_destroy(Solution &sol) {\n        vector<int> nonzero;\n        nonzero.reserve(49);\n        for (int pos = 0; pos < 49; pos++) {\n            if (sol.pos_cid[pos] != 0) nonzero.push_back(pos);\n        }\n        if (nonzero.empty()) return {};\n\n        int r = 1 + rng.next_int(min(4, (int)nonzero.size()));\n        for (int i = 0; i < r; i++) {\n            int j = i + rng.next_int((int)nonzero.size() - i);\n            swap(nonzero[i], nonzero[j]);\n        }\n\n        vector<int> removed;\n        removed.reserve(r);\n        for (int i = 0; i < r; i++) {\n            int pos = nonzero[i];\n            remove_position_combo(sol, pos);\n            removed.push_back(pos);\n        }\n        return removed;\n    }\n\n    vector<int> weak_destroy(Solution &sol) {\n        struct Item {\n            i64 gain;\n            int cost;\n            int pos;\n        };\n        vector<Item> cand;\n        cand.reserve(49);\n\n        for (int pos = 0; pos < 49; pos++) {\n            int cid = sol.pos_cid[pos];\n            if (cid == 0) continue;\n            i64 g = gain_remove_pos(sol.board, pos, combos[cid].add); // larger => weaker\n            cand.push_back({g, (int)combos[cid].cost, pos});\n        }\n        if (cand.empty()) return {};\n\n        sort(cand.begin(), cand.end(), [&](const Item& a, const Item& b) {\n            i64 lhs = a.gain * b.cost;\n            i64 rhs = b.gain * a.cost;\n            if (lhs != rhs) return lhs > rhs;\n            if (a.gain != b.gain) return a.gain > b.gain;\n            return a.pos < b.pos;\n        });\n\n        int limit = min((int)cand.size(), 6);\n        int r = 1 + rng.next_int(min(4, limit));\n\n        vector<int> chosen;\n        chosen.reserve(r);\n        for (int i = 0; i < r; i++) {\n            int idx = rng.next_int(limit);\n            chosen.push_back(cand[idx].pos);\n        }\n        sort(chosen.begin(), chosen.end());\n        chosen.erase(unique(chosen.begin(), chosen.end()), chosen.end());\n\n        vector<int> removed;\n        removed.reserve(chosen.size());\n        for (int pos : chosen) {\n            remove_position_combo(sol, pos);\n            removed.push_back(pos);\n        }\n        return removed;\n    }\n\n    vector<int> cluster_destroy(Solution &sol) {\n        int center = rng.next_int(49);\n        int cp = center / 7, cq = center % 7;\n\n        vector<int> cand;\n        for (int dp = -1; dp <= 1; dp++) {\n            for (int dq = -1; dq <= 1; dq++) {\n                int np = cp + dp, nq = cq + dq;\n                if (0 <= np && np < 7 && 0 <= nq && nq < 7) {\n                    int pos = np * 7 + nq;\n                    if (sol.pos_cid[pos] != 0) cand.push_back(pos);\n                }\n            }\n        }\n        if (cand.empty()) return random_destroy(sol);\n\n        int r = 1 + rng.next_int(min(5, (int)cand.size()));\n        for (int i = 0; i < r; i++) {\n            int j = i + rng.next_int((int)cand.size() - i);\n            swap(cand[i], cand[j]);\n        }\n\n        vector<int> removed;\n        removed.reserve(r);\n        for (int i = 0; i < r; i++) {\n            int pos = cand[i];\n            remove_position_combo(sol, pos);\n            removed.push_back(pos);\n        }\n        sort(removed.begin(), removed.end());\n        removed.erase(unique(removed.begin(), removed.end()), removed.end());\n        return removed;\n    }\n\n    vector<int> expand_focus_positions(const vector<int>& removed) const {\n        if (removed.empty()) return all_positions;\n\n        bool vis[49] = {};\n        vector<int> focus;\n        focus.reserve(49);\n\n        for (int pos : removed) {\n            int p = pos / 7, q = pos % 7;\n            for (int dp = -2; dp <= 2; dp++) {\n                for (int dq = -2; dq <= 2; dq++) {\n                    int np = p + dp, nq = q + dq;\n                    if (0 <= np && np < 7 && 0 <= nq && nq < 7) {\n                        int npos = np * 7 + nq;\n                        if (!vis[npos]) {\n                            vis[npos] = true;\n                            focus.push_back(npos);\n                        }\n                    }\n                }\n            }\n        }\n        return focus;\n    }\n\n    void output(const Solution &sol) const {\n        cout << sol.used << '\\n';\n        for (int pos = 0; pos < 49; pos++) {\n            int p = pos / 7;\n            int q = pos % 7;\n            for (int t = 0; t < sol.pos_count[pos]; t++) {\n                cout << (int)sol.pos_ids[pos][t] << ' ' << p << ' ' << q << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int CNUM = 25;\nstatic constexpr long long INF_SCORE = (long long)4e18;\n\nstatic chrono::steady_clock::time_point g_start;\nstatic constexpr double TIME_LIMIT_SEC = 2.75;\n\nstatic inline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\nstatic inline bool time_over() {\n    return elapsed_sec() > TIME_LIMIT_SEC;\n}\n\nstruct Result {\n    long long score = INF_SCORE;\n    vector<string> out;\n};\n\nstruct Planner {\n    int A[N][N];\n\n    // parameters\n    int handoff;      // 2 or 3\n    int mode;         // 0 greedy, 1 source-batch\n    int policy;       // tie-break metric\n    int ready_bias;   // source-batch threshold\n    int slot_policy;  // 0 balanced, 1 source-biased\n\n    int src_of[CNUM], pos_of[CNUM];\n\n    int idx[N];\n    bool done[CNUM];\n    int need[N];\n\n    // 0 hidden/source, 1 buffered, 2 dispatched\n    int loc_type[CNUM];\n    pair<int,int> buf_pos[CNUM];\n    int buffer_occ[N][N];\n\n    int done_cnt = 0;\n\n    struct Crane {\n        bool alive = true;\n        int r = 0, c = 0;\n        int hold = -1;\n        bool large = false;\n    };\n    Crane cranes[N];\n\n    // simulator state\n    int cont[N][N];\n    int arrival_idx[N];\n\n    vector<string> out;\n    int T = 0;\n    bool illegal = false;\n\n    vector<int> dispatched[N];\n\n    Planner(const int inputA[N][N], int handoff_, int mode_, int policy_, int ready_bias_, int slot_policy_)\n        : handoff(handoff_), mode(mode_), policy(policy_), ready_bias(ready_bias_), slot_policy(slot_policy_) {\n        memset(src_of, -1, sizeof(src_of));\n        memset(pos_of, -1, sizeof(pos_of));\n        memset(idx, 0, sizeof(idx));\n        memset(done, 0, sizeof(done));\n        memset(need, 0, sizeof(need));\n        memset(loc_type, 0, sizeof(loc_type));\n        memset(buffer_occ, -1, sizeof(buffer_occ));\n        memset(cont, -1, sizeof(cont));\n        memset(arrival_idx, 0, sizeof(arrival_idx));\n        out.assign(N, \"\");\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) A[i][j] = inputA[i][j];\n    }\n\n    static int mdist(pair<int,int> a, pair<int,int> b) {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    pair<int,int> cur_pos() const { return {cranes[0].r, cranes[0].c}; }\n    bool assigned_row(int d) const { return d >= 1; }\n    bool is_move(char ch) const { return ch == 'U' || ch == 'D' || ch == 'L' || ch == 'R'; }\n    bool startup_phase() const { return T < 4; }\n\n    void update_need(int d) {\n        while (need[d] <= d * N + (N - 1) && done[need[d]]) need[d]++;\n    }\n\n    bool row_pending_small(int d) const {\n        if (!assigned_row(d)) return false;\n        int t = need[d];\n        if (t > d * N + (N - 1)) return false;\n        if (cranes[d].hold == t) return true;\n        if (cont[d][handoff] == t) return true;\n        return false;\n    }\n\n    void mark_done(int id) {\n        if (id < 0 || id >= CNUM || done[id]) return;\n        done[id] = true;\n        loc_type[id] = 2;\n        done_cnt++;\n        update_need(id / N);\n    }\n\n    char decide_small(int d) const {\n        if (T < 4) return 'R'; // move to col 4\n\n        const Crane &cr = cranes[d];\n        if (cr.hold != -1) {\n            if (cr.c < 4) return 'R';\n            return 'Q';\n        } else {\n            if (cr.c == 4) {\n                if (cont[d][handoff] == need[d]) return 'L';\n                return '.';\n            }\n            if (cr.c > handoff) {\n                if (cont[d][handoff] == need[d]) return 'L';\n                return 'R';\n            }\n            if (cr.c == handoff) {\n                if (cont[d][handoff] == need[d]) return 'P';\n                return 'R';\n            }\n            if (cr.c < 4) return 'R';\n            return '.';\n        }\n    }\n\n    void step_sim(const string &act) {\n        if (illegal) return;\n\n        // 1. arrivals\n        for (int r = 0; r < N; r++) {\n            if (arrival_idx[r] >= N) continue;\n            if (cont[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (!blocked) {\n                cont[r][0] = A[r][arrival_idx[r]];\n                arrival_idx[r]++;\n            }\n        }\n\n        array<pair<int,int>, N> oldp, newp;\n        for (int i = 0; i < N; i++) {\n            oldp[i] = {cranes[i].r, cranes[i].c};\n            newp[i] = oldp[i];\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) {\n                if (act[i] != '.') illegal = true;\n                continue;\n            }\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n\n            if (a == 'B') {\n                if (cranes[i].hold != -1) illegal = true;\n                continue;\n            }\n            if (a == 'P') {\n                if (cranes[i].hold != -1 || cont[r][c] == -1) illegal = true;\n                continue;\n            }\n            if (a == 'Q') {\n                if (cranes[i].hold == -1 || cont[r][c] != -1) illegal = true;\n                continue;\n            }\n\n            if (is_move(a)) {\n                int nr = r, nc = c;\n                if (a == 'U') nr--;\n                if (a == 'D') nr++;\n                if (a == 'L') nc--;\n                if (a == 'R') nc++;\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) illegal = true;\n                nr = max(0, min(N - 1, nr));\n                nc = max(0, min(N - 1, nc));\n                if (!cranes[i].large && cranes[i].hold != -1 && cont[nr][nc] != -1) illegal = true;\n                newp[i] = {nr, nc};\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive || act[i] == 'B') continue;\n            for (int j = i + 1; j < N; j++) {\n                if (!cranes[j].alive || act[j] == 'B') continue;\n                if (newp[i] == newp[j]) illegal = true;\n                bool mi = (newp[i] != oldp[i]);\n                bool mj = (newp[j] != oldp[j]);\n                if (mi && mj && newp[i] == oldp[j] && newp[j] == oldp[i]) illegal = true;\n            }\n        }\n        if (illegal) return;\n\n        for (int i = 0; i < N; i++) {\n            if (cranes[i].alive && act[i] == 'B') cranes[i].alive = false;\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (cranes[i].alive && is_move(act[i])) {\n                cranes[i].r = newp[i].first;\n                cranes[i].c = newp[i].second;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n            if (a == 'P') {\n                cranes[i].hold = cont[r][c];\n                cont[r][c] = -1;\n            } else if (a == 'Q') {\n                cont[r][c] = cranes[i].hold;\n                cranes[i].hold = -1;\n            }\n        }\n\n        for (int r = 0; r < N; r++) {\n            if (cont[r][4] != -1) {\n                dispatched[r].push_back(cont[r][4]);\n                cont[r][4] = -1;\n            }\n        }\n    }\n\n    void emit(char a0) {\n        if (illegal) return;\n        string act(N, '.');\n        act[0] = a0;\n        for (int i = 1; i < N; i++) act[i] = decide_small(i);\n\n        int small_pick_id[N], small_q_id[N];\n        for (int i = 0; i < N; i++) small_pick_id[i] = small_q_id[i] = -1;\n\n        for (int d = 1; d < N; d++) {\n            if (act[d] == 'P') small_pick_id[d] = cont[d][handoff];\n            if (act[d] == 'Q') small_q_id[d] = cranes[d].hold;\n        }\n\n        for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n        step_sim(act);\n        T++;\n\n        if (illegal) return;\n\n        for (int d = 1; d < N; d++) {\n            if (small_pick_id[d] != -1) {\n                int id = small_pick_id[d];\n                if (buffer_occ[d][handoff] == id) buffer_occ[d][handoff] = -1;\n                if (loc_type[id] == 1) buf_pos[id] = {-1, -1};\n            }\n            if (small_q_id[d] != -1) {\n                mark_done(small_q_id[d]);\n            }\n        }\n    }\n\n    void move_to(int tr, int tc) {\n        int safe_col = startup_phase() ? 0 : (handoff - 1);\n        int mid = min(tc, safe_col);\n        while (!illegal && cranes[0].c > mid) emit('L');\n        while (!illegal && cranes[0].c < mid) emit('R');\n        while (!illegal && cranes[0].r < tr) emit('D');\n        while (!illegal && cranes[0].r > tr) emit('U');\n        while (!illegal && cranes[0].c < tc) emit('R');\n        while (!illegal && cranes[0].c > tc) emit('L');\n    }\n\n    bool ready_id(int id) const {\n        if (id < 0 || id >= CNUM || done[id]) return false;\n        if (loc_type[id] == 1) return buf_pos[id].first != -1;\n        int s = src_of[id];\n        return pos_of[id] == idx[s];\n    }\n\n    vector<pair<int,int>> ordinary_slots() const {\n        vector<pair<int,int>> ret;\n\n        if (startup_phase()) {\n            for (int c = 1; c <= 3; c++) {\n                if (buffer_occ[0][c] == -1) ret.push_back({0, c});\n            }\n            return ret;\n        }\n\n        for (int r = 0; r < N; r++) if (buffer_occ[r][1] == -1) ret.push_back({r, 1});\n\n        if (handoff == 3) {\n            for (int r = 0; r < N; r++) if (buffer_occ[r][2] == -1) ret.push_back({r, 2});\n            if (buffer_occ[0][3] == -1) ret.push_back({0, 3});\n        } else {\n            if (buffer_occ[0][2] == -1) ret.push_back({0, 2});\n            if (buffer_occ[0][3] == -1) ret.push_back({0, 3});\n        }\n\n        for (int r = 0; r < N; r++) {\n            if (idx[r] == N && buffer_occ[r][0] == -1) ret.push_back({r, 0});\n        }\n        return ret;\n    }\n\n    vector<pair<int,int>> overflow_slots(int exclude_row = -1) const {\n        vector<pair<int,int>> ret;\n        if (startup_phase()) return ret;\n        for (int r = 1; r < N; r++) {\n            if (r == exclude_row) continue;\n            if (buffer_occ[r][3] != -1) continue;\n            if (row_pending_small(r)) continue;\n            ret.push_back({r, 3});\n        }\n        return ret;\n    }\n\n    pair<int,int> choose_slot(int src_row, int dest_row, bool allow_overflow = true, int exclude_overflow_row = -1) const {\n        pair<int,int> best = {-1, -1};\n        int best_score = INT_MAX;\n\n        auto eval = [&](int r, int c, int extra_penalty) {\n            int score = 0;\n            if (startup_phase()) {\n                score = c; // row0 startup stash\n            } else if (slot_policy == 0) {\n                score += abs(src_row - r);\n                score += abs(r - dest_row);\n                score += c;\n                if (r == dest_row) score -= 2;\n                if (c == 1) score -= 1;\n            } else {\n                score += 2 * abs(src_row - r);\n                score += abs(r - dest_row);\n                score += c;\n                if (r == src_row) score -= 2;\n                if (r == dest_row) score -= 1;\n                if (c == 1) score -= 1;\n            }\n            score += extra_penalty;\n\n            if (score < best_score || (score == best_score && make_pair(r, c) < best)) {\n                best_score = score;\n                best = {r, c};\n            }\n        };\n\n        for (auto [r, c] : ordinary_slots()) eval(r, c, 0);\n        if (allow_overflow) for (auto [r, c] : overflow_slots(exclude_overflow_row)) eval(r, c, 6);\n        return best;\n    }\n\n    struct ReadyCand {\n        int id = -1;\n        int cost = INT_MAX;\n    };\n    struct BatchCand {\n        int s = -1;\n        int target_id = -1;\n        int target_pos = -1;\n        int cost = INT_MAX;\n    };\n    struct PeelCand {\n        int s = -1;\n        int cost = INT_MAX;\n    };\n\n    vector<ReadyCand> ready_candidates() const {\n        vector<ReadyCand> res;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (startup_phase() && d > 0) continue;\n            if (!ready_id(t)) continue;\n\n            pair<int,int> loc = (loc_type[t] == 1 ? buf_pos[t] : make_pair(src_of[t], 0));\n            int cost = mdist(cp, loc);\n            cost += abs(loc.first - d) + (d == 0 ? 4 - loc.second : handoff - loc.second);\n\n            if (!startup_phase()) {\n                if (d > 0 && handoff == 2 && buffer_occ[d][3] != -1) cost += 5;\n                if (d > 0 && handoff == 3 && buffer_occ[d][3] != -1 && buffer_occ[d][3] != t) cost += 5;\n            }\n\n            res.push_back({t, cost});\n        }\n\n        sort(res.begin(), res.end(), [](auto &a, auto &b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.id < b.id;\n        });\n        return res;\n    }\n\n    vector<BatchCand> batch_candidates() const {\n        vector<BatchCand> res;\n        auto cp = cur_pos();\n\n        for (int s = 0; s < N; s++) {\n            if (idx[s] >= N) continue;\n\n            int best_pos = INT_MAX, best_id = -1;\n            for (int d = 0; d < N; d++) {\n                int t = need[d];\n                if (t > d * N + (N - 1)) continue;\n                if (assigned_row(d) && row_pending_small(d)) continue;\n                if (src_of[t] != s) continue;\n                if (pos_of[t] < idx[s]) continue;\n\n                if (pos_of[t] < best_pos || (pos_of[t] == best_pos && t < best_id)) {\n                    best_pos = pos_of[t];\n                    best_id = t;\n                }\n            }\n            if (best_id == -1) continue;\n\n            int depth = best_pos - idx[s];\n            int d = best_id / N;\n            int travel = abs(cp.first - s) + cp.second;\n            int deliver = abs(s - d) + (d == 0 ? 4 : handoff);\n\n            int metric;\n            if (policy == 0) metric = 12 * depth + travel + deliver;\n            else if (policy == 1) metric = 10 * depth + 2 * travel + deliver;\n            else metric = 9 * depth + travel + 2 * deliver;\n\n            res.push_back({s, best_id, best_pos, metric});\n        }\n\n        sort(res.begin(), res.end(), [](auto &a, auto &b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.target_pos != b.target_pos) return a.target_pos < b.target_pos;\n            if (a.target_id != b.target_id) return a.target_id < b.target_id;\n            return a.s < b.s;\n        });\n        return res;\n    }\n\n    vector<PeelCand> peel_candidates() const {\n        vector<PeelCand> res;\n        auto cp = cur_pos();\n\n        for (int s = 0; s < N; s++) {\n            if (idx[s] >= N) continue;\n            int x = A[s][idx[s]];\n            int d = x / N;\n            int travel = abs(cp.first - s) + cp.second;\n\n            int best_depth = 9;\n            for (int rr = 0; rr < N; rr++) {\n                int t = need[rr];\n                if (t > rr * N + (N - 1)) continue;\n                if (assigned_row(rr) && row_pending_small(rr)) continue;\n                if (src_of[t] == s && pos_of[t] >= idx[s]) {\n                    best_depth = min(best_depth, pos_of[t] - idx[s]);\n                }\n            }\n\n            int cost = 3 * travel + 4 * best_depth;\n            if (x == need[d] && !(assigned_row(d) && row_pending_small(d)) && (!startup_phase() || d == 0)) cost -= 20;\n            res.push_back({s, cost});\n        }\n\n        sort(res.begin(), res.end(), [](auto &a, auto &b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.s < b.s;\n        });\n        return res;\n    }\n\n    ReadyCand choose_ready_opt() const {\n        auto v = ready_candidates();\n        if (v.empty()) return {};\n        return v[0];\n    }\n\n    BatchCand choose_batch_opt() const {\n        auto v = batch_candidates();\n        if (v.empty()) return {};\n        return v[0];\n    }\n\n    int choose_target_row() const {\n        int best_d = -1;\n        long long best_metric = INF_SCORE;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (startup_phase() && d > 0 && ready_id(t)) continue;\n            if (ready_id(t)) continue;\n\n            int s = src_of[t];\n            int depth = pos_of[t] - idx[s];\n            int front = (idx[s] < N ? A[s][idx[s]] : INT_MAX);\n            int travel = abs(cp.first - s) + cp.second;\n            int align = abs(s - d);\n\n            long long metric;\n            if (policy == 0) {\n                metric = (((long long)depth) << 30) + (((long long)front) << 15) + (((long long)travel) << 7) + d;\n            } else if (policy == 1) {\n                metric = (((long long)depth) << 30) + (((long long)travel) << 15) + (((long long)front) << 7) + d;\n            } else {\n                metric = ((10LL * depth + 2LL * travel + align) << 10) + d;\n            }\n\n            if (metric < best_metric) {\n                best_metric = metric;\n                best_d = d;\n            }\n        }\n        return best_d;\n    }\n\n    void pick_id(int id) {\n        if (loc_type[id] == 1) {\n            auto [r, c] = buf_pos[id];\n            move_to(r, c);\n            if (illegal) return;\n            emit('P');\n            if (illegal) return;\n            buffer_occ[r][c] = -1;\n            loc_type[id] = 0;\n            buf_pos[id] = {-1, -1};\n        } else {\n            int s = src_of[id];\n            move_to(s, 0);\n            if (illegal) return;\n            emit('P');\n            if (illegal) return;\n            idx[s]++;\n        }\n    }\n\n    void direct_dispatch_large_row0(int id) {\n        move_to(0, 4);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        mark_done(id);\n    }\n\n    void place_on_row_slot(int id, int d);\n\n    void clear_cell(int r, int c) {\n        int x = buffer_occ[r][c];\n        if (x == -1) return;\n        if (r >= 1 && row_pending_small(r)) return;\n\n        move_to(r, c);\n        if (illegal) return;\n        emit('P');\n        if (illegal) return;\n\n        buffer_occ[r][c] = -1;\n        loc_type[x] = 0;\n        buf_pos[x] = {-1, -1};\n\n        int d = x / N;\n        if (d == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (!startup_phase() && d > 0 && x == need[d] && !row_pending_small(d)) {\n            place_on_row_slot(x, d);\n            return;\n        }\n\n        auto slot = choose_slot(r, d, true, r);\n        if (slot.first == -1) {\n            if (startup_phase()) {\n                while (!illegal && startup_phase()) emit('.');\n                if (illegal) return;\n                slot = choose_slot(r, d, true, r);\n            }\n        }\n        if (slot.first == -1) {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(x);\n            return;\n        }\n\n        move_to(slot.first, slot.second);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void dispatch_ready(int id) {\n        pick_id(id);\n        if (illegal) return;\n        int d = id / N;\n        if (d == 0) direct_dispatch_large_row0(id);\n        else place_on_row_slot(id, d);\n    }\n\n    void buffer_or_handle_front(int s) {\n        int x = A[s][idx[s]];\n        move_to(s, 0);\n        if (illegal) return;\n        emit('P');\n        if (illegal) return;\n        idx[s]++;\n\n        int d = x / N;\n        if (d == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (!startup_phase() && d > 0 && x == need[d] && !row_pending_small(d)) {\n            place_on_row_slot(x, d);\n            return;\n        }\n\n        auto slot = choose_slot(s, d, true, -1);\n        if (slot.first == -1 && startup_phase()) {\n            while (!illegal && startup_phase()) emit('.');\n            if (illegal) return;\n            if (d > 0 && x == need[d] && !row_pending_small(d)) {\n                place_on_row_slot(x, d);\n                return;\n            }\n            slot = choose_slot(s, d, true, -1);\n        }\n\n        if (slot.first == -1) {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(x);\n            return;\n        }\n\n        move_to(slot.first, slot.second);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void process_source_batch(const BatchCand &bo) {\n        int s = bo.s;\n        int target_pos = bo.target_pos;\n        while (!illegal && T < 10000 && idx[s] <= target_pos) {\n            int before = idx[s];\n            buffer_or_handle_front(s);\n            if (illegal) return;\n            if (idx[s] <= before) break;\n        }\n    }\n\n    void process_source_batch_source(int s) {\n        auto v = batch_candidates();\n        for (auto &bo : v) {\n            if (bo.s == s) {\n                process_source_batch(bo);\n                return;\n            }\n        }\n        if (idx[s] < N) buffer_or_handle_front(s);\n    }\n\n    long long exact_score() const {\n        if (illegal) return INF_SCORE;\n\n        long long M0 = T, M1 = 0, M2 = 0, M3 = 0;\n        int total_dispatched = 0;\n\n        for (int r = 0; r < N; r++) {\n            vector<int> corr;\n            for (int x : dispatched[r]) {\n                total_dispatched++;\n                if (x / N != r) M2++;\n                else corr.push_back(x);\n            }\n            for (int i = 0; i < (int)corr.size(); i++) {\n                for (int j = i + 1; j < (int)corr.size(); j++) {\n                    if (corr[i] > corr[j]) M1++;\n                }\n            }\n        }\n        M3 = CNUM - total_dispatched;\n        return M0 + 100LL * M1 + 10000LL * M2 + 1000000LL * M3;\n    }\n\n    void init() {\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int x = A[r][j];\n                src_of[x] = r;\n                pos_of[x] = j;\n            }\n        }\n        for (int d = 0; d < N; d++) need[d] = d * N;\n\n        for (int i = 0; i < N; i++) {\n            cranes[i].alive = true;\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].hold = -1;\n            cranes[i].large = (i == 0);\n        }\n    }\n\n    void run_default_loop() {\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            if (mode == 0) {\n                auto ro = choose_ready_opt();\n                if (ro.id != -1) {\n                    dispatch_ready(ro.id);\n                    continue;\n                }\n                int d = choose_target_row();\n                if (d == -1) {\n                    bool pending = false;\n                    for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n                    if (pending) {\n                        if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n                        else emit('.');\n                        continue;\n                    }\n                    break;\n                }\n                int t = need[d];\n                int s = src_of[t];\n                if (idx[s] >= N) break;\n                buffer_or_handle_front(s);\n            } else {\n                auto ro = choose_ready_opt();\n                auto bo = choose_batch_opt();\n\n                if (bo.s == -1) {\n                    if (ro.id != -1) {\n                        dispatch_ready(ro.id);\n                        continue;\n                    }\n                    bool pending = false;\n                    for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n                    if (pending) {\n                        if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n                        else emit('.');\n                        continue;\n                    }\n                    break;\n                }\n\n                bool take_ready = false;\n                if (ro.id != -1 && ro.cost <= bo.cost + ready_bias) take_ready = true;\n\n                if (take_ready) dispatch_ready(ro.id);\n                else process_source_batch(bo);\n            }\n        }\n    }\n\n    void drain_and_fallback() {\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            bool pending = false;\n            for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n            if (!pending) break;\n            if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n            else emit('.');\n        }\n\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            auto ro = choose_ready_opt();\n            if (ro.id != -1) {\n                dispatch_ready(ro.id);\n                continue;\n            }\n            bool progressed = false;\n            for (int s = 0; s < N && !progressed; s++) {\n                if (idx[s] < N) {\n                    buffer_or_handle_front(s);\n                    progressed = true;\n                }\n            }\n            if (progressed) continue;\n\n            bool pending = false;\n            for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n            if (pending) {\n                if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n                else emit('.');\n                continue;\n            }\n            break;\n        }\n    }\n\n    void finish_default() {\n        run_default_loop();\n        drain_and_fallback();\n    }\n\n    Result make_result() const {\n        Result res;\n        res.score = exact_score();\n        res.out = out.empty() ? vector<string>(N, \".\") : out;\n        if (res.out[0].empty()) res.out.assign(N, \".\");\n        return res;\n    }\n\n    struct Action {\n        int type; // 0 ready(id), 1 batch(source), 2 peel(source)\n        int val;\n        int est;\n    };\n\n    vector<Action> enumerate_actions(int max_total) const {\n        vector<Action> acts;\n\n        auto rc = ready_candidates();\n        auto bc = batch_candidates();\n        auto pc = peel_candidates();\n\n        int cap_ready = 4;\n        int cap_batch = 4;\n        int cap_peel  = 4;\n\n        for (int i = 0; i < (int)rc.size() && i < cap_ready; i++) {\n            acts.push_back({0, rc[i].id, rc[i].cost});\n        }\n        for (int i = 0; i < (int)bc.size() && i < cap_batch; i++) {\n            acts.push_back({1, bc[i].s, bc[i].cost + 1});\n        }\n        for (int i = 0; i < (int)pc.size() && i < cap_peel; i++) {\n            acts.push_back({2, pc[i].s, pc[i].cost + 2});\n        }\n\n        sort(acts.begin(), acts.end(), [](const Action &a, const Action &b) {\n            if (a.est != b.est) return a.est < b.est;\n            if (a.type != b.type) return a.type < b.type;\n            return a.val < b.val;\n        });\n\n        vector<Action> uniq;\n        for (auto &a : acts) {\n            bool dup = false;\n            for (auto &b : uniq) {\n                if (a.type == b.type && a.val == b.val) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) uniq.push_back(a);\n            if ((int)uniq.size() >= max_total) break;\n        }\n        return uniq;\n    }\n\n    void apply_action(const Action &a) {\n        if (a.type == 0) {\n            dispatch_ready(a.val);\n        } else if (a.type == 1) {\n            process_source_batch_source(a.val);\n        } else {\n            if (a.val >= 0 && a.val < N && idx[a.val] < N) buffer_or_handle_front(a.val);\n        }\n    }\n\n    long long eval_future(int depth_left, int max_actions) {\n        if (illegal) return INF_SCORE;\n        if (time_over()) {\n            finish_default();\n            return exact_score();\n        }\n        if (depth_left <= 0) {\n            finish_default();\n            return exact_score();\n        }\n\n        auto acts = enumerate_actions(max_actions);\n        if (acts.empty()) {\n            finish_default();\n            return exact_score();\n        }\n\n        long long best = INF_SCORE;\n        for (auto &a : acts) {\n            if (time_over()) break;\n            Planner tmp = *this;\n            tmp.apply_action(a);\n            if (tmp.illegal) continue;\n            best = min(best, tmp.eval_future(depth_left - 1, max_actions));\n        }\n\n        if (best == INF_SCORE) {\n            finish_default();\n            return exact_score();\n        }\n        return best;\n    }\n\n    Result solve_default() {\n        init();\n        finish_default();\n        return make_result();\n    }\n\n    Result solve_rollout(int depth, int max_actions) {\n        init();\n\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            if (time_over()) {\n                finish_default();\n                break;\n            }\n\n            auto acts = enumerate_actions(max_actions);\n            if (acts.empty()) {\n                finish_default();\n                break;\n            }\n\n            long long bestScore = INF_SCORE;\n            int bestIdx = -1;\n\n            for (int i = 0; i < (int)acts.size(); i++) {\n                if (time_over()) break;\n                Planner tmp = *this;\n                tmp.apply_action(acts[i]);\n                if (tmp.illegal) continue;\n                long long sc = tmp.eval_future(depth - 1, max_actions);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestIdx = i;\n                }\n            }\n\n            if (bestIdx == -1) {\n                finish_default();\n                break;\n            }\n            apply_action(acts[bestIdx]);\n        }\n\n        drain_and_fallback();\n        return make_result();\n    }\n};\n\nvoid Planner::place_on_row_slot(int id, int d) {\n    if (d == 0) {\n        direct_dispatch_large_row0(id);\n        return;\n    }\n\n    if (startup_phase()) {\n        auto slot = choose_slot(cranes[0].r, d, false, -1);\n        if (slot.first == -1) {\n            while (!illegal && startup_phase()) emit('.');\n            if (illegal) return;\n        } else {\n            move_to(slot.first, slot.second);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            loc_type[id] = 1;\n            buf_pos[id] = slot;\n            buffer_occ[slot.first][slot.second] = id;\n            return;\n        }\n    }\n\n    if (handoff == 3) {\n        if (buffer_occ[d][3] != -1 && buffer_occ[d][3] != id) {\n            clear_cell(d, 3);\n            if (illegal) return;\n        }\n        if (buffer_occ[d][3] == -1) {\n            move_to(d, 3);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            loc_type[id] = 1;\n            buf_pos[id] = {d, 3};\n            buffer_occ[d][3] = id;\n        } else {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(id);\n        }\n    } else {\n        if (buffer_occ[d][3] != -1) {\n            clear_cell(d, 3);\n            if (illegal) return;\n        }\n        if (buffer_occ[d][2] != -1 && buffer_occ[d][2] != id) {\n            clear_cell(d, 2);\n            if (illegal) return;\n        }\n        if (buffer_occ[d][2] == -1 && buffer_occ[d][3] == -1) {\n            move_to(d, 2);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            loc_type[id] = 1;\n            buf_pos[id] = {d, 2};\n            buffer_occ[d][2] = id;\n        } else {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(id);\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    int n;\n    cin >> n;\n    int A[N][N];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> A[i][j];\n\n    struct Variant {\n        int handoff, mode, policy, ready_bias, slot_policy;\n        int rollout_depth; // 0 means default only\n        int max_actions;\n    };\n\n    vector<Variant> vars = {\n        {2, 1, 1, 2, 1, 2, 7},\n        {3, 1, 1, 2, 1, 2, 7},\n        {2, 1, 1, 6, 1, 1, 8},\n        {3, 1, 1, 6, 1, 1, 8},\n        {2, 1, 1, 2, 1, 0, 0},\n        {3, 1, 1, 2, 1, 0, 0},\n        {2, 0, 2, 0, 0, 0, 0},\n        {3, 0, 1, 0, 0, 0, 0},\n    };\n\n    Result best;\n    for (auto &v : vars) {\n        if (time_over()) break;\n        Planner planner(A, v.handoff, v.mode, v.policy, v.ready_bias, v.slot_policy);\n        Result cur = (v.rollout_depth > 0)\n            ? planner.solve_rollout(v.rollout_depth, v.max_actions)\n            : planner.solve_default();\n        if (cur.score < best.score) best = cur;\n    }\n\n    if (best.out.empty()) best.out.assign(N, \".\");\n    for (int i = 0; i < N; i++) {\n        cout << best.out[i] << '\\n';\n    }\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int r, c;\n};\n\nstruct EvalInfo {\n    long long cost;\n    int borrow;\n};\n\nstruct Candidate {\n    long long cost;\n    int borrow;\n    vector<int> path;\n};\n\nstruct State {\n    vector<int> path;\n    vector<int> pos;\n    long long cost;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    int next_int(int n) { return (int)(next_u32() % (uint32_t)n); }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n};\n\nstatic constexpr long long INF64 = (1LL << 62);\n\nint N, M;\nvector<int> H1;\nlong long BASE_COST = 0;\n\nint rr_[400], cc_[400];\nint dist0_[400];\nint distmat_[400][400];\nbool adjmat_[400][400];\nvector<int> neigh_[400];\n\nchrono::steady_clock::time_point TIME_BEGIN;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - TIME_BEGIN).count();\n}\n\ninline bool better_eval(const EvalInfo& a, const EvalInfo& b) {\n    if (a.cost != b.cost) return a.cost < b.cost;\n    return a.borrow < b.borrow;\n}\n\nPoint apply_sym(Point p, int sym, int N) {\n    if (sym >= 4) {\n        p.c = N - 1 - p.c;\n        sym -= 4;\n    }\n    for (int k = 0; k < sym; k++) {\n        int nr = p.c;\n        int nc = N - 1 - p.r;\n        p.r = nr;\n        p.c = nc;\n    }\n    return p;\n}\n\nvector<Point> transform_order(const vector<Point>& base, int sym, bool rev, int N) {\n    vector<Point> v;\n    v.reserve(base.size());\n    for (auto p : base) v.push_back(apply_sym(p, sym, N));\n    if (rev) reverse(v.begin(), v.end());\n    return v;\n}\n\nbool validate_order(const vector<Point>& ord, int N, bool cycle) {\n    if ((int)ord.size() != N * N) return false;\n    vector<int> seen(N * N, 0);\n    for (auto p : ord) {\n        if (p.r < 0 || p.r >= N || p.c < 0 || p.c >= N) return false;\n        int id = p.r * N + p.c;\n        if (seen[id]) return false;\n        seen[id] = 1;\n    }\n    for (int i = 0; i + 1 < (int)ord.size(); i++) {\n        int d = abs(ord[i].r - ord[i + 1].r) + abs(ord[i].c - ord[i + 1].c);\n        if (d != 1) return false;\n    }\n    if (cycle) {\n        int d = abs(ord.back().r - ord.front().r) + abs(ord.back().c - ord.front().c);\n        if (d != 1) return false;\n    }\n    return true;\n}\n\nvector<Point> make_base_cycle(int N) {\n    vector<Point> cyc;\n    cyc.reserve(N * N);\n\n    for (int r = 0; r < N; r++) cyc.push_back({r, 0});\n    for (int c = 1; c < N; c++) {\n        if (c & 1) {\n            for (int r = N - 1; r >= 1; r--) cyc.push_back({r, c});\n        } else {\n            for (int r = 1; r < N; r++) cyc.push_back({r, c});\n        }\n    }\n    cyc.push_back({0, N - 1});\n    for (int c = N - 2; c >= 1; c--) cyc.push_back({0, c});\n\n    return cyc;\n}\n\nvector<Point> make_row_snake(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    for (int r = 0; r < N; r++) {\n        if ((r & 1) == 0) {\n            for (int c = 0; c < N; c++) ord.push_back({r, c});\n        } else {\n            for (int c = N - 1; c >= 0; c--) ord.push_back({r, c});\n        }\n    }\n    return ord;\n}\n\nvector<Point> make_spiral(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\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++) ord.push_back({top, c});\n        top++;\n        for (int r = top; r <= bottom; r++) ord.push_back({r, right});\n        right--;\n        if (top <= bottom) {\n            for (int c = right; c >= left; c--) ord.push_back({bottom, c});\n            bottom--;\n        }\n        if (left <= right) {\n            for (int r = bottom; r >= top; r--) ord.push_back({r, left});\n            left++;\n        }\n    }\n    return ord;\n}\n\nint sgn(int x) { return (x > 0) - (x < 0); }\n\nvoid gilbert2d(int x, int y, int ax, int ay, int bx, int by, vector<Point>& out) {\n    int w = abs(ax + ay);\n    int h = abs(bx + by);\n\n    int dax = sgn(ax), day = sgn(ay);\n    int dbx = sgn(bx), dby = sgn(by);\n\n    if (h == 1) {\n        for (int i = 0; i < w; i++) {\n            out.push_back({y, x});\n            x += dax;\n            y += day;\n        }\n        return;\n    }\n    if (w == 1) {\n        for (int i = 0; i < h; i++) {\n            out.push_back({y, x});\n            x += dbx;\n            y += dby;\n        }\n        return;\n    }\n\n    int ax2 = ax / 2, ay2 = ay / 2;\n    int bx2 = bx / 2, by2 = by / 2;\n    int w2 = abs(ax2 + ay2);\n    int h2 = abs(bx2 + by2);\n\n    if (2 * w > 3 * h) {\n        if ((w2 & 1) && (w > 2)) {\n            ax2 += dax;\n            ay2 += day;\n        }\n        gilbert2d(x, y, ax2, ay2, bx, by, out);\n        gilbert2d(x + ax2, y + ay2, ax - ax2, ay - ay2, bx, by, out);\n    } else {\n        if ((h2 & 1) && (h > 2)) {\n            bx2 += dbx;\n            by2 += dby;\n        }\n        gilbert2d(x, y, bx2, by2, ax2, ay2, out);\n        gilbert2d(x + bx2, y + by2, ax, ay, bx - bx2, by - by2, out);\n        gilbert2d(\n            x + (ax - dax) + (bx2 - dbx),\n            y + (ay - day) + (by2 - dby),\n            -bx2, -by2, -(ax - ax2), -(ay - ay2), out\n        );\n    }\n}\n\nvector<Point> make_gilbert(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    gilbert2d(0, 0, N, 0, 0, N, ord);\n    return ord;\n}\n\nvector<int> points_to_ids(const vector<Point>& v) {\n    vector<int> ids;\n    ids.reserve(v.size());\n    for (auto p : v) ids.push_back(p.r * N + p.c);\n    return ids;\n}\n\nvoid build_pos(const vector<int>& path, vector<int>& pos) {\n    pos.assign(M, -1);\n    for (int i = 0; i < M; i++) pos[path[i]] = i;\n}\n\nEvalInfo eval_path_direction(const vector<int>& path, bool rev) {\n    long long cur = 0, min_pref = 0, sum_pref = 0;\n    if (!rev) {\n        for (int i = 0; i < M; i++) {\n            cur += H1[path[i]];\n            if (cur < min_pref) min_pref = cur;\n            if (i + 1 < M) sum_pref += cur;\n        }\n        long long k = -min_pref;\n        int s = path[0], t = path[M - 1];\n        int ret = (k > 0 ? distmat_[s][t] : 0);\n        long long cost =\n            BASE_COST +\n            2LL * k +\n            100LL * (dist0_[s] + (M - 1) + ret) +\n            sum_pref +\n            k * 1LL * ((M - 1) + ret);\n        return {cost, (int)k};\n    } else {\n        for (int i = M - 1; i >= 0; i--) {\n            cur += H1[path[i]];\n            if (cur < min_pref) min_pref = cur;\n            if (i > 0) sum_pref += cur;\n        }\n        long long k = -min_pref;\n        int s = path[M - 1], t = path[0];\n        int ret = (k > 0 ? distmat_[s][t] : 0);\n        long long cost =\n            BASE_COST +\n            2LL * k +\n            100LL * (dist0_[s] + (M - 1) + ret) +\n            sum_pref +\n            k * 1LL * ((M - 1) + ret);\n        return {cost, (int)k};\n    }\n}\n\npair<EvalInfo, int> eval_cycle_best_shift(const vector<int>& cyc) {\n    static long long P[405];\n    static long long pref[410];\n\n    P[0] = 0;\n    for (int i = 0; i < M; i++) P[i + 1] = P[i] + H1[cyc[i]];\n\n    long long minP = P[0];\n    for (int st = 1; st < M; st++) minP = min(minP, P[st]);\n\n    pref[0] = 0;\n    for (int i = 0; i <= M; i++) pref[i + 1] = pref[i] + P[i];\n\n    EvalInfo best{INF64, 0};\n    int best_st = 0;\n\n    for (int st = 0; st < M; st++) {\n        if (P[st] != minP) continue;\n        long long sum1 = pref[M + 1] - pref[st + 1];\n        long long sum2 = (st >= 2 ? pref[st] - pref[1] : 0);\n        long long carry = sum1 + sum2 - 1LL * (M - 1) * P[st];\n\n        int s = cyc[st];\n        long long cost = BASE_COST + 100LL * (dist0_[s] + (M - 1)) + carry;\n        EvalInfo cur{cost, 0};\n        if (better_eval(cur, best)) {\n            best = cur;\n            best_st = st;\n        }\n    }\n    return {best, best_st};\n}\n\nvoid orient_best_inplace(vector<int>& path, EvalInfo& best_eval) {\n    EvalInfo best = eval_path_direction(path, false);\n    int mode = 0; // 0:fwd path, 1:rev path, 2:cycle cut fwd, 3:cycle cut rev\n    int best_st = 0;\n\n    EvalInfo revp = eval_path_direction(path, true);\n    if (better_eval(revp, best)) {\n        best = revp;\n        mode = 1;\n    }\n\n    if (adjmat_[path.front()][path.back()]) {\n        auto [cycf, stf] = eval_cycle_best_shift(path);\n        if (better_eval(cycf, best)) {\n            best = cycf;\n            mode = 2;\n            best_st = stf;\n        }\n\n        vector<int> rev_path = path;\n        reverse(rev_path.begin(), rev_path.end());\n        auto [cycr, str] = eval_cycle_best_shift(rev_path);\n        if (better_eval(cycr, best)) {\n            best = cycr;\n            mode = 3;\n            best_st = str;\n        }\n    }\n\n    if (mode == 1) {\n        reverse(path.begin(), path.end());\n    } else if (mode == 2) {\n        rotate(path.begin(), path.begin() + best_st, path.end());\n    } else if (mode == 3) {\n        reverse(path.begin(), path.end());\n        rotate(path.begin(), path.begin() + best_st, path.end());\n    }\n\n    best_eval = best;\n}\n\nuint64_t hash_order(const vector<int>& path) {\n    uint64_t h = 1469598103934665603ull;\n    for (int x : path) {\n        h ^= (uint64_t)(x + 1);\n        h *= 1099511628211ull;\n    }\n    return h;\n}\n\nbool random_backbite(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    int first_side = rng.next_int(2);\n    for (int rep = 0; rep < 2; rep++) {\n        int side = first_side ^ rep;\n        if (side == 0) {\n            int ep = path[0];\n            int forbidden = path[1];\n            int cand[4], cnt = 0;\n            for (int u : neigh_[ep]) if (u != forbidden) cand[cnt++] = u;\n            if (cnt == 0) continue;\n            int u = cand[rng.next_int(cnt)];\n            int i = pos[u];\n            if (i <= 1) continue;\n            reverse(path.begin(), path.begin() + i);\n            for (int k = 0; k < i; k++) pos[path[k]] = k;\n            return true;\n        } else {\n            int ep = path[M - 1];\n            int forbidden = path[M - 2];\n            int cand[4], cnt = 0;\n            for (int u : neigh_[ep]) if (u != forbidden) cand[cnt++] = u;\n            if (cnt == 0) continue;\n            int u = cand[rng.next_int(cnt)];\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            reverse(path.begin() + i + 1, path.end());\n            for (int k = i + 1; k < M; k++) pos[path[k]] = k;\n            return true;\n        }\n    }\n    return false;\n}\n\nbool random_two_opt(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    for (int tries = 0; tries < 32; tries++) {\n        int i = rng.next_int(M - 1);\n        int a = path[i];\n        int b = path[i + 1];\n        int prev = (i > 0 ? path[i - 1] : -1);\n\n        int candj[4], cnt = 0;\n        for (int u : neigh_[a]) {\n            if (u == b || u == prev) continue;\n            int j = pos[u];\n            if (j <= i + 1) continue;\n            if (j == M - 1 || adjmat_[b][path[j + 1]]) {\n                if (!(i == 0 && j == M - 1)) candj[cnt++] = j;\n            }\n        }\n        if (cnt == 0) continue;\n\n        int j = candj[rng.next_int(cnt)];\n        reverse(path.begin() + i + 1, path.begin() + j + 1);\n        for (int k = i + 1; k <= j; k++) pos[path[k]] = k;\n        return true;\n    }\n    return false;\n}\n\nbool mutate_path(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    int t = rng.next_int(100);\n    if (t < 55) {\n        if (random_backbite(path, pos, rng)) return true;\n        return random_two_opt(path, pos, rng);\n    } else {\n        if (random_two_opt(path, pos, rng)) return true;\n        return random_backbite(path, pos, rng);\n    }\n}\n\nbool find_best_neighbor(\n    const vector<int>& path,\n    const vector<int>& pos,\n    const EvalInfo& ref_ev,\n    vector<int>& best_path,\n    EvalInfo& best_ev,\n    double deadline_sec,\n    bool require_improvement\n) {\n    bool found = false;\n    EvalInfo best{INF64, INT_MAX};\n\n    auto consider = [&](vector<int>& cand) {\n        EvalInfo ev;\n        orient_best_inplace(cand, ev);\n        if (require_improvement && !better_eval(ev, ref_ev)) return;\n        if (!found || better_eval(ev, best)) {\n            found = true;\n            best = ev;\n            best_path = cand;\n        }\n    };\n\n    // front backbite\n    {\n        int ep = path[0];\n        int forbidden = path[1];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i <= 1) continue;\n            vector<int> cand = path;\n            reverse(cand.begin(), cand.begin() + i);\n            consider(cand);\n        }\n    }\n\n    // back backbite\n    {\n        int ep = path[M - 1];\n        int forbidden = path[M - 2];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.end());\n            consider(cand);\n        }\n    }\n\n    // exhaustive 2-opt-like reversals\n    for (int i = 0; i < M - 1; i++) {\n        if ((i & 31) == 0 && elapsed_sec() > deadline_sec) break;\n\n        int a = path[i];\n        int b = path[i + 1];\n        int prev = (i > 0 ? path[i - 1] : -1);\n\n        for (int u : neigh_[a]) {\n            if (u == b || u == prev) continue;\n            int j = pos[u];\n            if (j <= i + 1) continue;\n            if (i == 0 && j == M - 1) continue;\n            if (j != M - 1 && !adjmat_[b][path[j + 1]]) continue;\n\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.begin() + j + 1);\n            consider(cand);\n        }\n    }\n\n    if (!found) return false;\n    best_ev = best;\n    return true;\n}\n\nbool best_improving_move(vector<int>& path, vector<int>& pos, EvalInfo& cur_ev, double deadline_sec) {\n    vector<int> best_path;\n    EvalInfo best_ev;\n    if (!find_best_neighbor(path, pos, cur_ev, best_path, best_ev, deadline_sec, true)) return false;\n    path.swap(best_path);\n    build_pos(path, pos);\n    cur_ev = best_ev;\n    return true;\n}\n\nvoid greedy_local_opt(vector<int>& path, EvalInfo& ev, int max_steps, double deadline_sec) {\n    orient_best_inplace(path, ev);\n    vector<int> pos;\n    build_pos(path, pos);\n\n    for (int step = 0; step < max_steps; step++) {\n        if (elapsed_sec() > deadline_sec) break;\n        if (!best_improving_move(path, pos, ev, deadline_sec)) break;\n    }\n}\n\nvoid collect_backbite_variants(const vector<int>& path, const vector<int>& pos, vector<vector<int>>& out) {\n    out.clear();\n\n    {\n        int ep = path[0];\n        int forbidden = path[1];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i <= 1) continue;\n            vector<int> cand = path;\n            reverse(cand.begin(), cand.begin() + i);\n            out.push_back(move(cand));\n        }\n    }\n    {\n        int ep = path[M - 1];\n        int forbidden = path[M - 2];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.end());\n            out.push_back(move(cand));\n        }\n    }\n}\n\nbool double_backbite_intensify(vector<int>& path, EvalInfo& ev, double deadline_sec) {\n    vector<int> pos;\n    build_pos(path, pos);\n\n    vector<vector<int>> firsts;\n    collect_backbite_variants(path, pos, firsts);\n\n    bool improved = false;\n    EvalInfo best_ev = ev;\n    vector<int> best_path = path;\n\n    for (auto cand1 : firsts) {\n        if (elapsed_sec() > deadline_sec) break;\n\n        EvalInfo ev1;\n        orient_best_inplace(cand1, ev1);\n        greedy_local_opt(cand1, ev1, 6, deadline_sec);\n        if (better_eval(ev1, best_ev)) {\n            best_ev = ev1;\n            best_path = cand1;\n            improved = true;\n        }\n\n        if (elapsed_sec() > deadline_sec) break;\n\n        vector<int> pos1;\n        build_pos(cand1, pos1);\n        vector<vector<int>> seconds;\n        collect_backbite_variants(cand1, pos1, seconds);\n\n        for (auto cand2 : seconds) {\n            if (elapsed_sec() > deadline_sec) break;\n            EvalInfo ev2;\n            orient_best_inplace(cand2, ev2);\n            greedy_local_opt(cand2, ev2, 6, deadline_sec);\n            if (better_eval(ev2, best_ev)) {\n                best_ev = ev2;\n                best_path = cand2;\n                improved = true;\n            }\n        }\n    }\n\n    if (improved) {\n        path.swap(best_path);\n        ev = best_ev;\n    }\n    return improved;\n}\n\nchar dir_between(int a, int b) {\n    if (rr_[b] == rr_[a] + 1 && cc_[b] == cc_[a]) return 'D';\n    if (rr_[b] == rr_[a] - 1 && cc_[b] == cc_[a]) return 'U';\n    if (rr_[b] == rr_[a] && cc_[b] == cc_[a] + 1) return 'R';\n    return 'L';\n}\n\nvoid move_manhattan(int& cr, int& cc, int tr, int tc, vector<string>& ans) {\n    while (cr < tr) ans.push_back(\"D\"), cr++;\n    while (cr > tr) ans.push_back(\"U\"), cr--;\n    while (cc < tc) ans.push_back(\"R\"), cc++;\n    while (cc > tc) ans.push_back(\"L\"), cc--;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    TIME_BEGIN = chrono::steady_clock::now();\n\n    cin >> N;\n    M = N * N;\n\n    vector<vector<int>> h(N, vector<int>(N));\n    H1.assign(M, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> h[i][j];\n            int id = i * N + j;\n            H1[id] = h[i][j];\n            BASE_COST += llabs((long long)h[i][j]);\n        }\n    }\n\n    if (BASE_COST == 0) return 0;\n\n    for (int id = 0; id < M; id++) {\n        rr_[id] = id / N;\n        cc_[id] = id % N;\n        dist0_[id] = rr_[id] + cc_[id];\n    }\n    for (int a = 0; a < M; a++) {\n        neigh_[a].clear();\n        for (int b = 0; b < M; b++) {\n            distmat_[a][b] = abs(rr_[a] - rr_[b]) + abs(cc_[a] - cc_[b]);\n            adjmat_[a][b] = (distmat_[a][b] == 1);\n        }\n        int r = rr_[a], c = cc_[a];\n        if (r > 0) neigh_[a].push_back((r - 1) * N + c);\n        if (r + 1 < N) neigh_[a].push_back((r + 1) * N + c);\n        if (c > 0) neigh_[a].push_back(r * N + (c - 1));\n        if (c + 1 < N) neigh_[a].push_back(r * N + (c + 1));\n    }\n\n    uint64_t seed = 0x9e3779b97f4a7c15ull;\n    for (int i = 0; i < M; i++) {\n        seed ^= (uint64_t)(H1[i] + 128 + 1009 * i);\n        seed ^= seed << 13;\n        seed ^= seed >> 7;\n        seed ^= seed << 17;\n    }\n    XorShift64 rng(seed);\n\n    vector<Point> cyc0 = make_base_cycle(N);\n    vector<Point> snake0 = make_row_snake(N);\n    vector<Point> spiral0 = make_spiral(N);\n    vector<Point> gilbert0 = make_gilbert(N);\n\n    vector<vector<Point>> base_cycles;\n    vector<vector<Point>> base_paths;\n\n    if (validate_order(cyc0, N, true)) base_cycles.push_back(cyc0);\n    if (validate_order(snake0, N, false)) base_paths.push_back(snake0);\n    if (validate_order(spiral0, N, false)) base_paths.push_back(spiral0);\n    if (validate_order(gilbert0, N, false)) base_paths.push_back(gilbert0);\n\n    vector<Candidate> pool;\n    pool.reserve(128);\n\n    for (auto& bc : base_cycles) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto ordp = transform_order(bc, sym, rev, N);\n                if (!validate_order(ordp, N, true)) continue;\n                auto ids = points_to_ids(ordp);\n                auto [ev, st] = eval_cycle_best_shift(ids);\n                rotate(ids.begin(), ids.begin() + st, ids.end());\n                pool.push_back({ev.cost, ev.borrow, move(ids)});\n            }\n        }\n    }\n\n    for (auto& bp : base_paths) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto ordp = transform_order(bp, sym, rev, N);\n                if (!validate_order(ordp, N, false)) continue;\n                auto ids = points_to_ids(ordp);\n                EvalInfo ev;\n                orient_best_inplace(ids, ev);\n                pool.push_back({ev.cost, ev.borrow, move(ids)});\n            }\n        }\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.borrow < b.borrow;\n    });\n\n    Candidate global_best = pool[0];\n    vector<Candidate> elites;\n    const int ELITE_MAX = 16;\n\n    auto push_elite = [&](const vector<int>& path, const EvalInfo& ev) {\n        uint64_t hs = hash_order(path);\n        for (auto& e : elites) {\n            if (hash_order(e.path) == hs) return;\n        }\n        elites.push_back({ev.cost, ev.borrow, path});\n        sort(elites.begin(), elites.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.borrow < b.borrow;\n        });\n        if ((int)elites.size() > ELITE_MAX) elites.resize(ELITE_MAX);\n    };\n\n    auto update_global = [&](const vector<int>& path, const EvalInfo& ev) {\n        EvalInfo cur{global_best.cost, global_best.borrow};\n        if (better_eval(ev, cur)) {\n            global_best.cost = ev.cost;\n            global_best.borrow = ev.borrow;\n            global_best.path = path;\n        }\n        push_elite(path, ev);\n    };\n\n    for (int i = 0; i < min<int>((int)pool.size(), 12); i++) {\n        EvalInfo ev{pool[i].cost, pool[i].borrow};\n        push_elite(pool[i].path, ev);\n    }\n\n    vector<vector<int>> seeds;\n    {\n        unordered_set<uint64_t> used;\n        used.reserve(512);\n        for (auto& cand : pool) {\n            uint64_t hs = hash_order(cand.path);\n            if (used.insert(hs).second) {\n                seeds.push_back(cand.path);\n                if ((int)seeds.size() >= 12) break;\n            }\n        }\n        for (int idx : {16, 24, 36, 48}) {\n            if (idx < (int)pool.size()) {\n                uint64_t hs = hash_order(pool[idx].path);\n                if (used.insert(hs).second) seeds.push_back(pool[idx].path);\n            }\n        }\n        if (seeds.empty()) seeds.push_back(global_best.path);\n    }\n\n    const double TOTAL_TL = 1.92;\n    const double SA_END = 1.58;\n\n    // early seed polish\n    for (int i = 0; i < (int)seeds.size() && i < 6; i++) {\n        if (elapsed_sec() > 0.24) break;\n        EvalInfo ev;\n        greedy_local_opt(seeds[i], ev, 6, 0.24);\n        update_global(seeds[i], ev);\n    }\n\n    auto choose_elite_path = [&]() -> const vector<int>& {\n        if (elites.empty()) return global_best.path;\n        int lim = min<int>(8, elites.size());\n        double x = rng.next_double();\n        int idx = min(lim - 1, (int)(x * x * lim));\n        return elites[idx].path;\n    };\n\n    auto make_state = [&](const vector<int>& base_path, int perturb_steps) -> State {\n        State st;\n        st.path = base_path;\n        build_pos(st.path, st.pos);\n\n        for (int t = 0; t < perturb_steps; t++) {\n            mutate_path(st.path, st.pos, rng);\n        }\n\n        EvalInfo ev;\n        orient_best_inplace(st.path, ev);\n\n        if (elapsed_sec() < 0.62) {\n            greedy_local_opt(st.path, ev, 2, 0.62);\n        }\n\n        build_pos(st.path, st.pos);\n        st.cost = ev.cost;\n        update_global(st.path, ev);\n        return st;\n    };\n\n    vector<State> states;\n    for (int i = 0; i < (int)seeds.size() && i < 8; i++) {\n        states.push_back(make_state(seeds[i], 0));\n    }\n    for (int i = 0; i < (int)seeds.size() && i < 8; i++) {\n        states.push_back(make_state(seeds[i], 16 + 8 * i));\n    }\n    if (states.empty()) {\n        states.push_back(make_state(global_best.path, 0));\n    }\n\n    double next_restart = 0.34;\n\n    while (elapsed_sec() < SA_END) {\n        int idx = rng.next_int((int)states.size());\n        State& cur = states[idx];\n\n        vector<int> cand_path = cur.path;\n        vector<int> cand_pos = cur.pos;\n\n        int kicks = 1 + (rng.next_int(100) < 22 ? 2 : 0);\n        bool ok = false;\n        for (int t = 0; t < kicks; t++) ok |= mutate_path(cand_path, cand_pos, rng);\n        if (!ok) continue;\n\n        EvalInfo cand_ev;\n        orient_best_inplace(cand_path, cand_ev);\n\n        double frac = elapsed_sec() / SA_END;\n        double T0 = 1800.0, T1 = 10.0;\n        double temp = T0 * pow(T1 / T0, frac);\n\n        bool accept = false;\n        if (cand_ev.cost <= cur.cost) {\n            accept = true;\n        } else {\n            double prob = exp((double)(cur.cost - cand_ev.cost) / temp);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.path.swap(cand_path);\n            build_pos(cur.path, cur.pos);\n            cur.cost = cand_ev.cost;\n\n            EvalInfo gcur{global_best.cost, global_best.borrow};\n            if (better_eval(cand_ev, gcur) && elapsed_sec() < SA_END - 0.04) {\n                greedy_local_opt(cur.path, cand_ev, 2, SA_END - 0.01);\n                build_pos(cur.path, cur.pos);\n                cur.cost = cand_ev.cost;\n            }\n            update_global(cur.path, cand_ev);\n        }\n\n        if (elapsed_sec() >= next_restart && elapsed_sec() < SA_END - 0.05) {\n            int worst = 0;\n            for (int i = 1; i < (int)states.size(); i++) {\n                if (states[i].cost > states[worst].cost) worst = i;\n            }\n            const vector<int>& base = choose_elite_path();\n            states[worst] = make_state(base, 20 + rng.next_int(20));\n            next_restart += 0.34;\n        }\n    }\n\n    // deterministic polish on some elites\n    for (int i = 0; i < (int)elites.size() && i < 5; i++) {\n        if (elapsed_sec() > 1.72) break;\n        vector<int> cand = elites[i].path;\n        EvalInfo ev{elites[i].cost, elites[i].borrow};\n        greedy_local_opt(cand, ev, 20, 1.72);\n        update_global(cand, ev);\n    }\n\n    // elite-guided perturb + climb\n    while (elapsed_sec() < 1.84) {\n        const vector<int>& base = choose_elite_path();\n        vector<int> cand = base;\n        vector<int> pos;\n        build_pos(cand, pos);\n\n        int kick = 3 + rng.next_int(8);\n        if (rng.next_int(100) < 18) kick += 10;\n        for (int t = 0; t < kick; t++) mutate_path(cand, pos, rng);\n\n        EvalInfo ev;\n        orient_best_inplace(cand, ev);\n        greedy_local_opt(cand, ev, 8, 1.84);\n        update_global(cand, ev);\n    }\n\n    // moderate strong intensification: double-backbite on best and top elites\n    {\n        int lim = min<int>(3, elites.size());\n        for (int i = 0; i < lim; i++) {\n            if (elapsed_sec() > 1.885) break;\n            vector<int> cand = elites[i].path;\n            EvalInfo ev{elites[i].cost, elites[i].borrow};\n            greedy_local_opt(cand, ev, 8, 1.865);\n            double_backbite_intensify(cand, ev, 1.885);\n            update_global(cand, ev);\n        }\n    }\n\n    // limited breakout: only a couple of exact best-neighbor escapes\n    {\n        vector<int> cur = global_best.path;\n        EvalInfo cur_ev{global_best.cost, global_best.borrow};\n        greedy_local_opt(cur, cur_ev, 12, 1.895);\n        update_global(cur, cur_ev);\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(16);\n        seen.insert(hash_order(cur));\n\n        for (int step = 0; step < 2 && elapsed_sec() < 1.905; step++) {\n            vector<int> pos;\n            build_pos(cur, pos);\n\n            vector<int> nxt;\n            EvalInfo nxt_ev;\n            if (!find_best_neighbor(cur, pos, cur_ev, nxt, nxt_ev, 1.905, false)) break;\n\n            uint64_t hs = hash_order(nxt);\n            if (!seen.insert(hs).second) break;\n\n            greedy_local_opt(nxt, nxt_ev, 8, 1.905);\n            update_global(nxt, nxt_ev);\n\n            cur.swap(nxt);\n            cur_ev = nxt_ev;\n        }\n    }\n\n    // final polish on best\n    {\n        vector<int> cand = global_best.path;\n        EvalInfo ev{global_best.cost, global_best.borrow};\n        greedy_local_opt(cand, ev, 40, TOTAL_TL - 0.005);\n        update_global(cand, ev);\n    }\n\n    vector<string> ans;\n    ans.reserve(3000);\n\n    int cr = 0, cc = 0;\n    int start_id = global_best.path.front();\n    move_manhattan(cr, cc, rr_[start_id], cc_[start_id], ans);\n\n    if (global_best.borrow > 0) {\n        ans.push_back(\"+\" + to_string(global_best.borrow));\n    }\n\n    for (int i = 0; i < M; i++) {\n        int id = global_best.path[i];\n        int v = H1[id];\n        if (v > 0) ans.push_back(\"+\" + to_string(v));\n        else if (v < 0) ans.push_back(\"-\" + to_string(-v));\n\n        if (i + 1 < M) {\n            char d = dir_between(global_best.path[i], global_best.path[i + 1]);\n            ans.push_back(string(1, d));\n        }\n    }\n\n    if (global_best.borrow > 0) {\n        int end_id = global_best.path.back();\n        cr = rr_[end_id];\n        cc = cc_[end_id];\n        move_manhattan(cr, cc, rr_[start_id], cc_[start_id], ans);\n        ans.push_back(\"-\" + to_string(global_best.borrow));\n    }\n\n    for (auto& s : ans) cout << s << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Seed {\n    array<int, 15> x{};\n    int value = 0;\n};\n\nclass Solver {\npublic:\n    static constexpr int MAXSUM = 1500;\n\n    int N, M, T;\n    int S, P;\n\n    vector<Seed> seeds;\n\n    vector<vector<int>> adj;\n    vector<pair<int, int>> edges;\n    vector<int> deg;\n    vector<int> posOrder;\n    vector<int> blackPos, whitePos;\n\n    mt19937_64 rng;\n\n    // per-turn statistics\n    array<double, 15> rareW{};\n    array<double, 61> powHalf{};\n    vector<ll> weightedSeedValue;\n    vector<vector<int>> evalQ;\n\n    // late-turn pair CDF cache\n    vector<array<float, MAXSUM + 1>> pairCDF;\n\n    Solver(int N_, int M_, int T_)\n        : N(N_), M(M_), T(T_), S(2 * N_ * (N_ - 1)), P(N_ * N_),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        buildGrid();\n        powHalf[0] = 1.0;\n        for (int i = 1; i <= 60; i++) powHalf[i] = powHalf[i - 1] * 0.5;\n    }\n\n    void buildGrid() {\n        adj.assign(P, {});\n        deg.assign(P, 0);\n        edges.clear();\n        blackPos.clear();\n        whitePos.clear();\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                if (((r + c) & 1) == 0) blackPos.push_back(p);\n                else whitePos.push_back(p);\n\n                if (c + 1 < N) {\n                    int q = r * N + (c + 1);\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n                if (r + 1 < N) {\n                    int q = (r + 1) * N + c;\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n            }\n        }\n        for (int p = 0; p < P; p++) deg[p] = (int)adj[p].size();\n\n        vector<pair<array<int, 5>, int>> ord;\n        ord.reserve(P);\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                int dist = abs(2 * r - (N - 1)) + abs(2 * c - (N - 1));\n                ord.push_back({{{dist, -deg[p], ((r + c) & 1), r, c}}, p});\n            }\n        }\n        sort(ord.begin(), ord.end());\n        posOrder.clear();\n        for (auto &e : ord) posOrder.push_back(e.second);\n    }\n\n    bool readSeeds() {\n        seeds.assign(S, Seed());\n        for (int i = 0; i < S; i++) {\n            int sum = 0;\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> seeds[i].x[j])) return false;\n                sum += seeds[i].x[j];\n            }\n            seeds[i].value = sum;\n        }\n        return true;\n    }\n\n    void buildTurnStatistics(int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n\n        array<int, 15> best1{}, best2{}, cntNear{};\n        for (int l = 0; l < M; l++) {\n            int mx1 = -1, mx2 = -1;\n            for (int i = 0; i < S; i++) {\n                int v = seeds[i].x[l];\n                if (v > mx1) {\n                    mx2 = mx1;\n                    mx1 = v;\n                } else if (v > mx2) {\n                    mx2 = v;\n                }\n            }\n            int cnt = 0;\n            for (int i = 0; i < S; i++) {\n                if (seeds[i].x[l] >= mx1 - 1) cnt++;\n            }\n            best1[l] = mx1;\n            best2[l] = max(0, mx2);\n            cntNear[l] = max(1, cnt);\n        }\n\n        double sumW = 0.0;\n        for (int l = 0; l < M; l++) {\n            double scarcity = 1.0 / cntNear[l];\n            double gapRatio = (double)(best1[l] - best2[l]) / max(1, best1[l]);\n            double w = 1.0 + (0.55 * scarcity + 0.90 * gapRatio) * (0.25 + 1.35 * g);\n            rareW[l] = w;\n            sumW += w;\n        }\n        double norm = (double)M / sumW;\n        for (int l = 0; l < M; l++) rareW[l] *= norm;\n\n        weightedSeedValue.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            double s = 0.0;\n            for (int l = 0; l < M; l++) s += rareW[l] * seeds[i].x[l];\n            weightedSeedValue[i] = (ll)llround(100.0 * s);\n        }\n\n        evalQ.assign(S, vector<int>(S, 0));\n        double betaEval = 1.65 + 0.20 * (1.0 - g);\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0;\n                double mean = 0.5 * (seeds[i].value + seeds[j].value);\n                double diff2 = 0.0;\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    opt += max(a, b);\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n                }\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + betaEval * sigma);\n                int v = (int)llround(q * 100.0);\n                evalQ[i][j] = evalQ[j][i] = v;\n            }\n        }\n    }\n\n    vector<vector<ll>> makeScoreMatrix(int scheme, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n        double alphaBalanced = 0.25 + 0.45 * g;\n        double alphaRare = 0.35 + 0.40 * g;\n        double beta = 1.45 + 0.30 * (1.0 - g);\n\n        vector<vector<ll>> sc(S, vector<ll>(S, 0));\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0, mean = 0.5 * (seeds[i].value + seeds[j].value), diff2 = 0.0;\n                double optw = 0.0, meanw = 0.0, diffw2 = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    int mx = max(a, b);\n\n                    opt += mx;\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n\n                    optw += rareW[l] * mx;\n                    meanw += 0.5 * rareW[l] * (a + b);\n                    double dw = rareW[l] * d;\n                    diffw2 += dw * dw;\n                }\n\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + beta * sigma);\n\n                double sigmaw = 0.5 * sqrt(diffw2);\n                double qw = min(optw, meanw + beta * sigmaw);\n\n                double val = 0.0;\n                switch (scheme) {\n                    case 0: val = alphaBalanced * opt + (1.0 - alphaBalanced) * q; break;\n                    case 1: val = alphaRare * optw + (1.0 - alphaRare) * qw; break;\n                    case 2: val = opt; break;\n                    case 3: val = q; break;\n                    case 4: val = qw; break;\n                    case 5: val = optw; break;\n                    case 6: val = q * q / 1000.0; break;\n                    default: val = q; break;\n                }\n\n                ll iv = (ll)llround(val * 100.0);\n                sc[i][j] = sc[j][i] = iv;\n            }\n        }\n        return sc;\n    }\n\n    vector<ll> computeIndividualPotential(const vector<vector<ll>>& sc, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n        int K = min(5, S - 1);\n\n        vector<ll> ind(S, 0);\n        vector<ll> tmp;\n        tmp.reserve(S - 1);\n\n        for (int i = 0; i < S; i++) {\n            tmp.clear();\n            for (int j = 0; j < S; j++) {\n                if (i == j) continue;\n                tmp.push_back(sc[i][j]);\n            }\n            if (K < (int)tmp.size()) {\n                nth_element(tmp.begin(), tmp.begin() + K, tmp.end(), greater<ll>());\n            }\n            ll sumTop = 0;\n            for (int k = 0; k < K; k++) sumTop += tmp[k];\n\n            ll bias = 25LL * seeds[i].value + (ll)llround((12.0 + 18.0 * g) * (weightedSeedValue[i] / 100.0));\n            ind[i] = sumTop / K + bias;\n        }\n        return ind;\n    }\n\n    vector<int> initAssignment(const vector<vector<ll>>& sc, const vector<ll>& ind, int mode, int noiseScale) {\n        vector<int> assign(P, -1);\n        vector<char> used(S, false);\n\n        if (mode == 1) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                return weightedSeedValue[a] > weightedSeedValue[b];\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        if (mode == 2) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (ind[a] != ind[b]) return ind[a] > ind[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        if (mode == 3) {\n            array<int, 15> bestNow{};\n            bestNow.fill(0);\n\n            for (int idx = 0; idx < P; idx++) {\n                ll bestScore = LLONG_MIN;\n                int bestSeed = -1;\n\n                for (int s = 0; s < S; s++) if (!used[s]) {\n                    ll gain = 0;\n                    for (int l = 0; l < M; l++) {\n                        int v = seeds[s].x[l];\n                        if (v > bestNow[l]) {\n                            gain += (ll)llround(100.0 * rareW[l] * (v - bestNow[l]));\n                        }\n                    }\n                    ll score = gain + weightedSeedValue[s] / 6 + 20LL * seeds[s].value;\n                    if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                    if (score > bestScore || (score == bestScore && (rng() & 1ULL))) {\n                        bestScore = score;\n                        bestSeed = s;\n                    }\n                }\n\n                assign[posOrder[idx]] = bestSeed;\n                used[bestSeed] = true;\n                for (int l = 0; l < M; l++) bestNow[l] = max(bestNow[l], seeds[bestSeed].x[l]);\n            }\n            return assign;\n        }\n\n        if (mode == 4) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (weightedSeedValue[a] != weightedSeedValue[b]) return weightedSeedValue[a] > weightedSeedValue[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        for (int p : posOrder) {\n            int fixedCnt = 0;\n            for (int nb : adj[p]) if (assign[nb] != -1) fixedCnt++;\n\n            ll bestSc = LLONG_MIN;\n            int bestSeed = -1;\n\n            for (int s = 0; s < S; s++) if (!used[s]) {\n                ll score = 1LL * (deg[p] - fixedCnt) * ind[s];\n                for (int nb : adj[p]) {\n                    if (assign[nb] != -1) score += sc[s][assign[nb]];\n                }\n                if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                if (score > bestSc || (score == bestSc && (rng() & 1ULL))) {\n                    bestSc = score;\n                    bestSeed = s;\n                }\n            }\n\n            assign[p] = bestSeed;\n            used[bestSeed] = true;\n        }\n\n        return assign;\n    }\n\n    ll calcObjective(const vector<int>& assign, const vector<vector<ll>>& sc) const {\n        ll res = 0;\n        for (auto [u, v] : edges) res += sc[assign[u]][assign[v]];\n        return res;\n    }\n\n    vector<int> hungarianMax(const vector<vector<ll>>& a) const {\n        int n = (int)a.size();\n        int m = (int)a[0].size();\n        const ll INF = (1LL << 60);\n\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF;\n\n                for (int j = 1; j <= m; j++) if (!used[j]) {\n                    ll cur = -a[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    void optimizeColor(vector<int>& assign, const vector<vector<ll>>& sc,\n                       const vector<int>& group, const vector<int>& other) {\n        vector<char> banned(S, false);\n        for (int p : other) banned[assign[p]] = true;\n\n        vector<int> cand;\n        cand.reserve(S - (int)other.size());\n        for (int s = 0; s < S; s++) if (!banned[s]) cand.push_back(s);\n\n        int n = (int)group.size();\n        int m = (int)cand.size();\n        vector<vector<ll>> benefit(n, vector<ll>(m, 0));\n\n        for (int i = 0; i < n; i++) {\n            int p = group[i];\n            for (int j = 0; j < m; j++) {\n                int s = cand[j];\n                ll b = 0;\n                for (int nb : adj[p]) b += sc[s][assign[nb]];\n                benefit[i][j] = b;\n            }\n        }\n\n        vector<int> choice = hungarianMax(benefit);\n        for (int i = 0; i < n; i++) assign[group[i]] = cand[choice[i]];\n    }\n\n    ll coordinateAscent(vector<int>& assign, const vector<vector<ll>>& sc) {\n        ll obj = calcObjective(assign, sc);\n        for (int it = 0; it < 8; it++) {\n            ll old = obj;\n            optimizeColor(assign, sc, blackPos, whitePos);\n            optimizeColor(assign, sc, whitePos, blackPos);\n            obj = calcObjective(assign, sc);\n            if (obj <= old) break;\n        }\n        return obj;\n    }\n\n    ll deltaSwap(const vector<int>& assign, const vector<vector<ll>>& sc, int p, int q) const {\n        int a = assign[p];\n        int b = assign[q];\n        ll d = 0;\n\n        for (int nb : adj[p]) {\n            if (nb == q) continue;\n            d += sc[b][assign[nb]] - sc[a][assign[nb]];\n        }\n        for (int nb : adj[q]) {\n            if (nb == p) continue;\n            d += sc[a][assign[nb]] - sc[b][assign[nb]];\n        }\n        return d;\n    }\n\n    ll crossSwapImprove(vector<int>& assign, const vector<vector<ll>>& sc, ll obj) {\n        for (int pass = 0; pass < 6; pass++) {\n            ll bestDelta = 0;\n            int bp = -1, wq = -1;\n\n            for (int p : blackPos) {\n                for (int q : whitePos) {\n                    ll d = deltaSwap(assign, sc, p, q);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bp = p;\n                        wq = q;\n                    }\n                }\n            }\n            if (bestDelta <= 0) break;\n            swap(assign[bp], assign[wq]);\n            obj = coordinateAscent(assign, sc);\n        }\n        return obj;\n    }\n\n    void buildPairCDF() {\n        pairCDF.resize(S * S);\n        static double dp[MAXSUM + 1];\n        static double ndp[MAXSUM + 1];\n\n        for (int i = 0; i < S; i++) {\n            auto &selfCDF = pairCDF[i * S + i];\n            for (int s = 0; s <= MAXSUM; s++) {\n                selfCDF[s] = (s >= seeds[i].value ? 1.0f : 0.0f);\n            }\n\n            for (int j = i + 1; j < S; j++) {\n                for (int s = 0; s <= MAXSUM; s++) dp[s] = 0.0;\n                dp[0] = 1.0;\n                int curMax = 0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    int nextMax = curMax + max(a, b);\n                    for (int s = 0; s <= nextMax; s++) ndp[s] = 0.0;\n\n                    if (a == b) {\n                        for (int s = 0; s <= curMax; s++) ndp[s + a] += dp[s];\n                    } else {\n                        for (int s = 0; s <= curMax; s++) {\n                            double half = 0.5 * dp[s];\n                            ndp[s + a] += half;\n                            ndp[s + b] += half;\n                        }\n                    }\n\n                    curMax = nextMax;\n                    for (int s = 0; s <= curMax; s++) dp[s] = ndp[s];\n                }\n\n                auto &cdf = pairCDF[i * S + j];\n                double cum = 0.0;\n                for (int s = 0; s <= MAXSUM; s++) {\n                    if (s <= curMax) cum += dp[s];\n                    cdf[s] = (float)cum;\n                }\n                pairCDF[j * S + i] = cdf;\n            }\n        }\n    }\n\n    double exactExpectedMaxFast(const vector<int>& assign) const {\n        static double prodCDF[MAXSUM + 1];\n        for (int s = 0; s <= MAXSUM; s++) prodCDF[s] = 1.0;\n\n        for (auto [u, v] : edges) {\n            const auto &cdf = pairCDF[assign[u] * S + assign[v]];\n            for (int s = 0; s < MAXSUM; s++) {\n                prodCDF[s] *= (double)cdf[s];\n            }\n        }\n\n        double ans = 0.0;\n        for (int s = 0; s < MAXSUM; s++) ans += 1.0 - prodCDF[s];\n        return ans;\n    }\n\n    ll evaluateCandidate(const vector<int>& assign, int remTurns, bool useExactImmediate) const {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n\n        vector<int> qvals;\n        qvals.reserve(edges.size());\n        ll totalQ = 0;\n\n        vector<array<int, 15>> virt(edges.size());\n        array<int, 15> top1{}, top2{}, top3{};\n        top1.fill(0);\n        top2.fill(0);\n        top3.fill(0);\n\n        int ei = 0;\n        for (auto [u, v] : edges) {\n            int a = assign[u], b = assign[v];\n            int q = evalQ[a][b];\n            qvals.push_back(q);\n            totalQ += q;\n\n            for (int l = 0; l < M; l++) {\n                int mv = max(seeds[a].x[l], seeds[b].x[l]);\n                virt[ei][l] = mv;\n                if (mv >= top1[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = top1[l];\n                    top1[l] = mv;\n                } else if (mv >= top2[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = mv;\n                } else if (mv > top3[l]) {\n                    top3[l] = mv;\n                }\n            }\n            ei++;\n        }\n\n        sort(qvals.begin(), qvals.end(), greater<int>());\n        static const int W[10] = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55};\n\n        ll weightedTop = 0;\n        for (int i = 0; i < min<int>(10, qvals.size()); i++) {\n            weightedTop += 1LL * qvals[i] * W[i];\n        }\n        weightedTop /= 100;\n\n        double c2 = 0.45 + 0.25 * g;\n        double c3 = 0.20 * g;\n        double coverage = 0.0;\n        for (int l = 0; l < M; l++) {\n            coverage += top1[l] + c2 * top2[l] + c3 * top3[l];\n        }\n\n        int bestFuture = 0;\n        if (remTurns >= 2) {\n            for (int i = 0; i < (int)virt.size(); i++) {\n                for (int j = i + 1; j < (int)virt.size(); j++) {\n                    int s = 0;\n                    for (int l = 0; l < M; l++) s += max(virt[i][l], virt[j][l]);\n                    if (s > bestFuture) bestFuture = s;\n                }\n            }\n        }\n\n        double coordExp = 0.0;\n        double coordExpRare = 0.0;\n        if (remTurns >= 2) {\n            int diffBoth[102], diffMix[102];\n            for (int l = 0; l < M; l++) {\n                memset(diffBoth, 0, sizeof(diffBoth));\n                memset(diffMix, 0, sizeof(diffMix));\n\n                for (auto [u, v] : edges) {\n                    int a = seeds[assign[u]].x[l];\n                    int b = seeds[assign[v]].x[l];\n                    if (a > b) swap(a, b);\n\n                    if (a > 0) {\n                        diffBoth[0] += 1;\n                        diffBoth[a] -= 1;\n                    }\n                    if (a < b) {\n                        diffMix[a] += 1;\n                        diffMix[b] -= 1;\n                    }\n                }\n\n                int cntBoth = 0, cntMix = 0;\n                double emax = 0.0;\n                for (int t = 0; t < 100; t++) {\n                    cntBoth += diffBoth[t];\n                    cntMix += diffMix[t];\n                    double pleq = (cntBoth > 0 ? 0.0 : powHalf[cntMix]);\n                    emax += 1.0 - pleq;\n                }\n                coordExp += emax;\n                coordExpRare += rareW[l] * emax;\n            }\n        }\n\n        ll meta = 0;\n        meta += weightedTop;\n        meta += totalQ / 50;\n        meta += (ll)llround((25.0 + 80.0 * g) * coverage);\n        if (remTurns >= 2) meta += (ll)llround((15.0 + 70.0 * g) * bestFuture);\n        if (remTurns >= 2) {\n            meta += (ll)llround((18.0 + 55.0 * g) * coordExpRare);\n            meta += (ll)llround((2.0 + 8.0 * g) * coordExp);\n            if (remTurns == 2) meta += (ll)llround(30.0 * coordExpRare);\n        }\n\n        if (useExactImmediate) {\n            double exactImm = exactExpectedMaxFast(assign);\n            double wImm = 0.0;\n            if (remTurns == 4) wImm = 70.0;\n            else if (remTurns == 3) wImm = 80.0;\n            else if (remTurns == 2) wImm = 95.0;\n            meta += (ll)llround(wImm * exactImm);\n        }\n\n        return meta;\n    }\n\n    static uint64_t splitmix64(uint64_t x) {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        return x ^ (x >> 31);\n    }\n\n    uint64_t hashAssign(const vector<int>& assign) const {\n        uint64_t h = 0x123456789abcdef0ULL;\n        for (int v : assign) {\n            h ^= splitmix64((uint64_t)v + h);\n            h = (h << 7) | (h >> 57);\n        }\n        return h;\n    }\n\n    ll localReplaceDeltaEvalQ(const vector<int>& assign, int p, int newSeed) const {\n        int oldSeed = assign[p];\n        ll d = 0;\n        for (int nb : adj[p]) d += (ll)evalQ[newSeed][assign[nb]] - evalQ[oldSeed][assign[nb]];\n        return d;\n    }\n\n    ll localSwapDeltaEvalQ(const vector<int>& assign, int p, int q) const {\n        if (p == q) return 0;\n        int a = assign[p];\n        int b = assign[q];\n        ll d = 0;\n        for (int nb : adj[p]) {\n            if (nb == q) continue;\n            d += (ll)evalQ[b][assign[nb]] - evalQ[a][assign[nb]];\n        }\n        for (int nb : adj[q]) {\n            if (nb == p) continue;\n            d += (ll)evalQ[a][assign[nb]] - evalQ[b][assign[nb]];\n        }\n        return d;\n    }\n\n    struct Move {\n        ll delta;\n        int type; // 1 replace, 2 swap\n        int a, b;\n    };\n\n    static void trimTop(vector<Move>& mv, int K) {\n        if ((int)mv.size() > K) {\n            nth_element(mv.begin(), mv.begin() + K, mv.end(),\n                        [](const Move& x, const Move& y) { return x.delta > y.delta; });\n            mv.resize(K);\n        }\n        sort(mv.begin(), mv.end(),\n             [](const Move& x, const Move& y) { return x.delta > y.delta; });\n    }\n\n    vector<int> refineLateCandidate(vector<int> assign, int remTurns) {\n        if (remTurns > 3) return assign;\n\n        if (remTurns == 1) {\n            double cur = exactExpectedMaxFast(assign);\n\n            for (int pass = 0; pass < 2; pass++) {\n                vector<char> used(S, false);\n                for (int p = 0; p < P; p++) used[assign[p]] = true;\n                vector<int> unused;\n                for (int s = 0; s < S; s++) if (!used[s]) unused.push_back(s);\n\n                vector<Move> reps, swaps;\n                reps.reserve(P * (int)unused.size());\n                swaps.reserve(P * (P - 1) / 2);\n\n                for (int p = 0; p < P; p++) {\n                    for (int s : unused) {\n                        reps.push_back({localReplaceDeltaEvalQ(assign, p, s), 1, p, s});\n                    }\n                }\n                for (int p = 0; p < P; p++) {\n                    for (int q = p + 1; q < P; q++) {\n                        swaps.push_back({localSwapDeltaEvalQ(assign, p, q), 2, p, q});\n                    }\n                }\n\n                trimTop(reps, 28);\n                trimTop(swaps, 20);\n\n                vector<Move> candMoves;\n                candMoves.reserve(reps.size() + swaps.size());\n                for (auto &m : reps) candMoves.push_back(m);\n                for (auto &m : swaps) candMoves.push_back(m);\n\n                double best = cur;\n                int bestIdx = -1;\n                vector<int> tmp = assign;\n\n                for (int i = 0; i < (int)candMoves.size(); i++) {\n                    auto &mv = candMoves[i];\n                    if (mv.type == 1) {\n                        int old = tmp[mv.a];\n                        tmp[mv.a] = mv.b;\n                        double val = exactExpectedMaxFast(tmp);\n                        tmp[mv.a] = old;\n                        if (val > best + 1e-12) {\n                            best = val;\n                            bestIdx = i;\n                        }\n                    } else {\n                        swap(tmp[mv.a], tmp[mv.b]);\n                        double val = exactExpectedMaxFast(tmp);\n                        swap(tmp[mv.a], tmp[mv.b]);\n                        if (val > best + 1e-12) {\n                            best = val;\n                            bestIdx = i;\n                        }\n                    }\n                }\n\n                if (bestIdx == -1) break;\n                auto &mv = candMoves[bestIdx];\n                if (mv.type == 1) assign[mv.a] = mv.b;\n                else swap(assign[mv.a], assign[mv.b]);\n                cur = best;\n            }\n            return assign;\n        }\n\n        ll cur = evaluateCandidate(assign, remTurns, true);\n\n        for (int pass = 0; pass < 2; pass++) {\n            vector<char> used(S, false);\n            for (int p = 0; p < P; p++) used[assign[p]] = true;\n            vector<int> unused;\n            for (int s = 0; s < S; s++) if (!used[s]) unused.push_back(s);\n\n            vector<Move> reps, swaps;\n            reps.reserve(P * (int)unused.size());\n            swaps.reserve(P * (P - 1) / 2);\n\n            for (int p = 0; p < P; p++) {\n                for (int s : unused) {\n                    reps.push_back({localReplaceDeltaEvalQ(assign, p, s), 1, p, s});\n                }\n            }\n            for (int p = 0; p < P; p++) {\n                for (int q = p + 1; q < P; q++) {\n                    swaps.push_back({localSwapDeltaEvalQ(assign, p, q), 2, p, q});\n                }\n            }\n\n            trimTop(reps, 28);\n            trimTop(swaps, 20);\n\n            vector<Move> candMoves;\n            candMoves.reserve(reps.size() + swaps.size());\n            for (auto &m : reps) candMoves.push_back(m);\n            for (auto &m : swaps) candMoves.push_back(m);\n\n            ll best = cur;\n            int bestIdx = -1;\n            vector<int> tmp = assign;\n\n            for (int i = 0; i < (int)candMoves.size(); i++) {\n                auto &mv = candMoves[i];\n                if (mv.type == 1) {\n                    int old = tmp[mv.a];\n                    tmp[mv.a] = mv.b;\n                    ll val = evaluateCandidate(tmp, remTurns, true);\n                    tmp[mv.a] = old;\n                    if (val > best) {\n                        best = val;\n                        bestIdx = i;\n                    }\n                } else {\n                    swap(tmp[mv.a], tmp[mv.b]);\n                    ll val = evaluateCandidate(tmp, remTurns, true);\n                    swap(tmp[mv.a], tmp[mv.b]);\n                    if (val > best) {\n                        best = val;\n                        bestIdx = i;\n                    }\n                }\n            }\n\n            if (bestIdx == -1) break;\n            auto &mv = candMoves[bestIdx];\n            if (mv.type == 1) assign[mv.a] = mv.b;\n            else swap(assign[mv.a], assign[mv.b]);\n            cur = best;\n        }\n\n        return assign;\n    }\n\n    vector<int> decideLayout(int turn) {\n        int remTurns = T - turn;\n        buildTurnStatistics(remTurns);\n\n        bool useExactImmediate = (remTurns <= 4);\n        if (useExactImmediate) buildPairCDF();\n\n        struct Candidate {\n            vector<int> assign;\n            ll meta;\n        };\n\n        vector<Candidate> cands;\n        unordered_set<uint64_t> seen;\n        seen.reserve(256);\n\n        int schemeCount;\n        if (remTurns == 1) schemeCount = 7;\n        else if (remTurns <= 2) schemeCount = 7;\n        else schemeCount = 6;\n\n        for (int s = 0; s < schemeCount; s++) {\n            vector<vector<ll>> sc = makeScoreMatrix(s, remTurns);\n            vector<ll> ind = computeIndividualPotential(sc, remTurns);\n\n            vector<pair<int, int>> starts = {\n                {0, 0},\n                {1, 0},\n                {2, 0},\n                {3, 0},\n                {4, 0},\n                {0, 15000}\n            };\n\n            if (remTurns <= 2) {\n                starts.push_back({0, 30000});\n                starts.push_back({3, 8000});\n            } else if (remTurns <= 4) {\n                starts.push_back({0, 25000});\n            }\n\n            for (auto [mode, noise] : starts) {\n                vector<int> assign = initAssignment(sc, ind, mode, noise);\n                ll obj = coordinateAscent(assign, sc);\n                obj = crossSwapImprove(assign, sc, obj);\n                (void)obj;\n\n                uint64_t h = hashAssign(assign);\n                if (!seen.insert(h).second) continue;\n\n                ll meta = evaluateCandidate(assign, remTurns, useExactImmediate && remTurns >= 2);\n                cands.push_back({assign, meta});\n            }\n        }\n\n        if (remTurns >= 2) {\n            sort(cands.begin(), cands.end(), [&](const Candidate& a, const Candidate& b) {\n                return a.meta > b.meta;\n            });\n\n            if (remTurns <= 3) {\n                int L = min(3, (int)cands.size());\n                ll bestMeta = LLONG_MIN;\n                vector<int> bestAssign = cands[0].assign;\n\n                for (int i = 0; i < L; i++) {\n                    vector<int> refined = refineLateCandidate(cands[i].assign, remTurns);\n                    ll meta = evaluateCandidate(refined, remTurns, true);\n                    if (meta > bestMeta) {\n                        bestMeta = meta;\n                        bestAssign = refined;\n                    }\n                }\n                return bestAssign;\n            } else {\n                return cands[0].assign;\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [&](const Candidate& a, const Candidate& b) {\n            return a.meta > b.meta;\n        });\n\n        int L = min(4, (int)cands.size());\n        double bestE = -1e100;\n        ll bestMeta = LLONG_MIN;\n        vector<int> bestAssign = cands[0].assign;\n\n        for (int i = 0; i < L; i++) {\n            vector<int> refined = refineLateCandidate(cands[i].assign, 1);\n            double e = exactExpectedMaxFast(refined);\n            ll meta = cands[i].meta;\n            if (e > bestE + 1e-12 || (abs(e - bestE) <= 1e-12 && meta > bestMeta)) {\n                bestE = e;\n                bestMeta = meta;\n                bestAssign = refined;\n            }\n        }\n        return bestAssign;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    Solver solver(N, M, T);\n    if (!solver.readSeeds()) return 0;\n\n    for (int t = 0; t < T; t++) {\n        vector<int> assign = solver.decideLayout(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << assign[i * N + j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (!solver.readSeeds()) return 0;\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Block {\n    bool pickup;                  // true: source block, false: target block\n    vector<int> ids;              // selected ids\n    vector<int> order;            // estimated visiting order\n    long long moveCost = 0;       // estimated movement cost in this block\n    Pt endPt{0, 0};               // estimated endpoint after this block\n};\n\nstruct Plan {\n    int startIdx = 0;\n    int h = 1;\n    long long cost = (1LL << 60); // estimated total = 2 setup turns + movement\n    string name;\n    vector<Block> blocks;\n};\n\nstruct BlockSolution {\n    long long moveCost = (1LL << 60);\n    long long score = (1LL << 60); // moveCost + simple tail heuristic\n    vector<int> order;\n    Pt endPt{0, 0};\n};\n\nstruct ExecResult {\n    long long cost = (1LL << 60);\n    vector<string> ops;\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n    bool over(double limit_ms) const {\n        return ms() >= limit_ms;\n    }\n};\n\nstatic constexpr long long INF64 = (1LL << 60);\nstatic constexpr int INF = 1e9;\n\nint N, M, Vcap;\nvector<Pt> src, dst;\nint Qm;\n\nvector<vector<unsigned char>> SS, ST, TS, TT;\nvector<vector<int>> srcIdAt, dstIdAt;\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nstatic inline int dist_by_type(bool curIsSource, int curIdx, bool toSource, int toIdx) {\n    if (curIsSource) {\n        return toSource ? (int)SS[curIdx][toIdx] : (int)ST[curIdx][toIdx];\n    } else {\n        return toSource ? (int)TS[curIdx][toIdx] : (int)TT[curIdx][toIdx];\n    }\n}\n\nvector<int> make_start_candidates() {\n    vector<int> cand;\n    vector<char> used(Qm, false);\n\n    auto add = [&](int idx) {\n        if (0 <= idx && idx < Qm && !used[idx]) {\n            used[idx] = true;\n            cand.push_back(idx);\n        }\n    };\n\n    const int ALL_START_THRESHOLD = 160;\n    if (Qm <= ALL_START_THRESHOLD) {\n        for (int i = 0; i < Qm; i++) add(i);\n        return cand;\n    }\n\n    int minX = 0, maxX = 0, minY = 0, maxY = 0;\n    int minS = 0, maxS = 0, minD = 0, maxD = 0;\n    for (int i = 1; i < Qm; i++) {\n        if (src[i].x < src[minX].x) minX = i;\n        if (src[i].x > src[maxX].x) maxX = i;\n        if (src[i].y < src[minY].y) minY = i;\n        if (src[i].y > src[maxY].y) maxY = i;\n        if (src[i].x + src[i].y < src[minS].x + src[minS].y) minS = i;\n        if (src[i].x + src[i].y > src[maxS].x + src[maxS].y) maxS = i;\n        if (src[i].x - src[i].y < src[minD].x - src[minD].y) minD = i;\n        if (src[i].x - src[i].y > src[maxD].x - src[maxD].y) maxD = i;\n    }\n    add(minX); add(maxX); add(minY); add(maxY);\n    add(minS); add(maxS); add(minD); add(maxD);\n\n    vector<Pt> corners = {{0,0}, {0,N-1}, {N-1,0}, {N-1,N-1}};\n    for (auto c : corners) {\n        int best = 0, bestd = manhattan(src[0], c);\n        for (int i = 1; i < Qm; i++) {\n            int d = manhattan(src[i], c);\n            if (d < bestd) bestd = d, best = i;\n        }\n        add(best);\n    }\n\n    double cx = 0, cy = 0;\n    for (auto &p : src) cx += p.x, cy += p.y;\n    cx /= Qm;\n    cy /= Qm;\n\n    int nearC = 0, farC = 0;\n    double bestNear = 1e100, bestFar = -1.0;\n    for (int i = 0; i < Qm; i++) {\n        double dx = src[i].x - cx;\n        double dy = src[i].y - cy;\n        double v = dx * dx + dy * dy;\n        if (v < bestNear) bestNear = v, nearC = i;\n        if (v > bestFar) bestFar = v, farC = i;\n    }\n    add(nearC);\n    add(farC);\n\n    if (cand.empty()) add(0);\n    return cand;\n}\n\nlong long rough_simulate(int h, int startIdx) {\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    long long cost = 2;\n    bool curIsSource = true;\n    int curIdx = startIdx;\n    int load = 1;\n\n    while (!remS.empty() || load > 0) {\n        while (load < h && !remS.empty()) {\n            int bestPos = -1, bestId = -1, bestDist = INF;\n            if (curIsSource) {\n                const auto& row = SS[curIdx];\n                for (int pos = 0; pos < (int)remS.size(); pos++) {\n                    int id = remS[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            } else {\n                const auto& row = TS[curIdx];\n                for (int pos = 0; pos < (int)remS.size(); pos++) {\n                    int id = remS[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            }\n            cost += bestDist;\n            curIsSource = true;\n            curIdx = bestId;\n            load++;\n            remS[bestPos] = remS.back();\n            remS.pop_back();\n        }\n\n        while (load > 0) {\n            int bestPos = -1, bestId = -1, bestDist = INF;\n            if (curIsSource) {\n                const auto& row = ST[curIdx];\n                for (int pos = 0; pos < (int)remT.size(); pos++) {\n                    int id = remT[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            } else {\n                const auto& row = TT[curIdx];\n                for (int pos = 0; pos < (int)remT.size(); pos++) {\n                    int id = remT[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            }\n            cost += bestDist;\n            curIsSource = false;\n            curIdx = bestId;\n            load--;\n            remT[bestPos] = remT.back();\n            remT.pop_back();\n        }\n    }\n\n    return cost;\n}\n\nvector<vector<int>> generate_candidate_sets(const vector<int>& rem, const vector<Pt>& vec, const Pt& cur, int k) {\n    vector<pair<int,int>> arr;\n    arr.reserve(rem.size());\n    for (int id : rem) arr.push_back({manhattan(cur, vec[id]), id});\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    vector<vector<int>> res;\n    if (k <= 0 || k > (int)arr.size()) return res;\n\n    auto add_vec = [&](vector<int> v) {\n        sort(v.begin(), v.end());\n        if ((int)v.size() != k) return;\n        if (adjacent_find(v.begin(), v.end()) != v.end()) return;\n        res.push_back(move(v));\n    };\n\n    if (k <= 3) {\n        int P = min((int)arr.size(), 6);\n        vector<int> top(P);\n        for (int i = 0; i < P; i++) top[i] = arr[i].second;\n        if (k == 1) {\n            for (int i = 0; i < P; i++) add_vec({top[i]});\n        } else if (k == 2) {\n            for (int i = 0; i < P; i++) {\n                for (int j = i + 1; j < P; j++) add_vec({top[i], top[j]});\n            }\n        } else {\n            for (int i = 0; i < P; i++) {\n                for (int j = i + 1; j < P; j++) {\n                    for (int l = j + 1; l < P; l++) add_vec({top[i], top[j], top[l]});\n                }\n            }\n        }\n    } else {\n        vector<int> base;\n        for (int i = 0; i < k; i++) base.push_back(arr[i].second);\n        add_vec(base);\n\n        if ((int)arr.size() > k) {\n            vector<int> v = base;\n            v.back() = arr[k].second;\n            add_vec(v);\n        }\n        if ((int)arr.size() > k + 1 && k >= 2) {\n            vector<int> v = base;\n            v[k - 2] = arr[k].second;\n            v[k - 1] = arr[k + 1].second;\n            add_vec(v);\n        }\n    }\n\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    return res;\n}\n\nstatic inline int nearest_dist_excluding(\n    const Pt& p,\n    const vector<int>& rem,\n    const vector<Pt>& vec,\n    const vector<char>* excluded\n) {\n    int best = INF;\n    if (excluded) {\n        for (int id : rem) {\n            if ((*excluded)[id]) continue;\n            best = min(best, manhattan(p, vec[id]));\n        }\n    } else {\n        for (int id : rem) best = min(best, manhattan(p, vec[id]));\n    }\n    return best;\n}\n\nlong long tail_estimate(\n    const Pt& endPt,\n    bool pickup,\n    const vector<int>& ids,\n    const vector<int>& remS,\n    const vector<int>& remT,\n    int loadAfter,\n    int h,\n    int biasScale\n) {\n    vector<char> excluded(Qm, 0);\n    for (int id : ids) excluded[id] = 1;\n\n    int remSLeft = pickup ? (int)remS.size() - (int)ids.size() : (int)remS.size();\n    int remTLeft = pickup ? (int)remT.size() : (int)remT.size() - (int)ids.size();\n\n    int ns = INF, nt = INF;\n    if (loadAfter < h && remSLeft > 0) {\n        ns = nearest_dist_excluding(endPt, remS, src, pickup ? &excluded : nullptr);\n    }\n    if (loadAfter > 0 && remTLeft > 0) {\n        nt = nearest_dist_excluding(endPt, remT, dst, pickup ? nullptr : &excluded);\n    }\n\n    if (remSLeft == 0 && loadAfter == 0) return 0;\n    if (loadAfter == 0) return (ns >= INF ? INF64 / 4 : (long long)ns);\n    if (remSLeft == 0) return (nt >= INF ? INF64 / 4 : (long long)nt);\n    if (loadAfter == h) return (nt >= INF ? INF64 / 4 : (long long)nt);\n\n    long long a = (ns >= INF ? INF64 / 4 : (long long)ns + 1LL * biasScale * loadAfter);\n    long long b = (nt >= INF ? INF64 / 4 : (long long)nt + 1LL * biasScale * (h - loadAfter));\n    return min(a, b);\n}\n\nvoid two_opt_open_path(vector<int>& ord, bool pickup, const Pt& startPt) {\n    int k = (int)ord.size();\n    if (k <= 2) return;\n\n    auto ptOf = [&](int id) -> const Pt& {\n        return pickup ? src[id] : dst[id];\n    };\n\n    bool improved = true;\n    for (int iter = 0; iter < 4 && improved; iter++) {\n        improved = false;\n        for (int i = 0; i < k; i++) {\n            for (int j = i + 1; j < k; j++) {\n                const Pt& A = (i == 0 ? startPt : ptOf(ord[i - 1]));\n                const Pt& B = ptOf(ord[i]);\n                const Pt& C = ptOf(ord[j]);\n\n                long long delta = 0;\n                delta += manhattan(A, C) - manhattan(A, B);\n                if (j + 1 < k) {\n                    const Pt& D = ptOf(ord[j + 1]);\n                    delta += manhattan(B, D) - manhattan(C, D);\n                }\n                if (delta < 0) {\n                    reverse(ord.begin() + i, ord.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n    }\n}\n\nBlockSolution solve_block_fast(\n    const Pt& startPt,\n    const vector<int>& ids,\n    bool pickup,\n    const vector<int>& remS,\n    const vector<int>& remT,\n    int loadAfter,\n    int h,\n    int biasScale\n) {\n    static constexpr int EXACT_K = 8;\n\n    BlockSolution ans;\n    int k = (int)ids.size();\n    if (k == 0) {\n        ans.moveCost = 0;\n        ans.score = 0;\n        ans.endPt = startPt;\n        return ans;\n    }\n\n    vector<Pt> pts(k);\n    for (int i = 0; i < k; i++) pts[i] = pickup ? src[ids[i]] : dst[ids[i]];\n\n    if (k <= EXACT_K) {\n        int S = 1 << k;\n        vector<int> dp(S * k, INF);\n        vector<short> par(S * k, -1);\n\n        auto at = [&](int mask, int j) -> int& { return dp[mask * k + j]; };\n        auto pat = [&](int mask, int j) -> short& { return par[mask * k + j]; };\n\n        for (int j = 0; j < k; j++) at(1 << j, j) = manhattan(startPt, pts[j]);\n\n        for (int mask = 1; mask < S; mask++) {\n            for (int j = 0; j < k; j++) {\n                if (!(mask & (1 << j))) continue;\n                int cur = at(mask, j);\n                if (cur >= INF) continue;\n                int remMask = (S - 1) ^ mask;\n                for (int nj = 0; nj < k; nj++) {\n                    if (!(remMask & (1 << nj))) continue;\n                    int nmask = mask | (1 << nj);\n                    int nd = cur + manhattan(pts[j], pts[nj]);\n                    int& ref = at(nmask, nj);\n                    if (nd < ref) {\n                        ref = nd;\n                        pat(nmask, nj) = (short)j;\n                    }\n                }\n            }\n        }\n\n        int full = S - 1;\n        long long bestScore = INF64;\n        int bestEnd = -1;\n\n        for (int j = 0; j < k; j++) {\n            int base = at(full, j);\n            if (base >= INF) continue;\n            long long tail = tail_estimate(pts[j], pickup, ids, remS, remT, loadAfter, h, biasScale);\n            long long score = (long long)base + tail;\n            if (score < bestScore || (score == bestScore && (bestEnd == -1 || base < at(full, bestEnd)))) {\n                bestScore = score;\n                bestEnd = j;\n            }\n        }\n\n        if (bestEnd == -1) return ans;\n\n        vector<int> ordRev;\n        int mask = full, cur = bestEnd;\n        while (cur != -1) {\n            ordRev.push_back(ids[cur]);\n            int p = pat(mask, cur);\n            mask ^= 1 << cur;\n            cur = p;\n        }\n        reverse(ordRev.begin(), ordRev.end());\n\n        ans.moveCost = at(full, bestEnd);\n        ans.score = bestScore;\n        ans.order = move(ordRev);\n        ans.endPt = pts[bestEnd];\n        return ans;\n    }\n\n    vector<int> rem = ids;\n    vector<int> ord;\n    ord.reserve(k);\n    Pt cur = startPt;\n\n    while (!rem.empty()) {\n        int bestPos = -1, bestDist = INF;\n        for (int i = 0; i < (int)rem.size(); i++) {\n            const Pt& p = pickup ? src[rem[i]] : dst[rem[i]];\n            int d = manhattan(cur, p);\n            if (d < bestDist) {\n                bestDist = d;\n                bestPos = i;\n            }\n        }\n        int id = rem[bestPos];\n        cur = pickup ? src[id] : dst[id];\n        ord.push_back(id);\n        rem[bestPos] = rem.back();\n        rem.pop_back();\n    }\n\n    two_opt_open_path(ord, pickup, startPt);\n\n    long long mv = 0;\n    cur = startPt;\n    for (int id : ord) {\n        const Pt& p = pickup ? src[id] : dst[id];\n        mv += manhattan(cur, p);\n        cur = p;\n    }\n\n    ans.moveCost = mv;\n    ans.order = move(ord);\n    ans.endPt = cur;\n    ans.score = mv + tail_estimate(cur, pickup, ids, remS, remT, loadAfter, h, biasScale);\n    return ans;\n}\n\nvoid remove_ids_from_rem(vector<int>& rem, const vector<int>& ids) {\n    vector<char> mark(Qm, 0);\n    for (int id : ids) mark[id] = 1;\n    int w = 0;\n    for (int i = 0; i < (int)rem.size(); i++) {\n        if (!mark[rem[i]]) rem[w++] = rem[i];\n    }\n    rem.resize(w);\n}\n\nPlan make_fill_plan(int h, int startIdx, int biasScale, const Timer& timer, double limit_ms) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.cost = 2;\n    plan.name = \"fill:\" + to_string(h) + \":\" + to_string(startIdx) + \":\" + to_string(biasScale);\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    Pt cur = src[startIdx];\n    int load = 1;\n\n    while (!remS.empty() || load > 0) {\n        if (timer.over(limit_ms)) {\n            plan.cost = INF64;\n            return plan;\n        }\n\n        if (load < h && !remS.empty()) {\n            int need = min(h - load, (int)remS.size());\n            auto sets = generate_candidate_sets(remS, src, cur, need);\n\n            BlockSolution bestBS;\n            vector<int> bestIds;\n            for (auto& cand : sets) {\n                auto bs = solve_block_fast(cur, cand, true, remS, remT, load + need, h, biasScale);\n                if (bs.score < bestBS.score || (bs.score == bestBS.score && bs.moveCost < bestBS.moveCost)) {\n                    bestBS = move(bs);\n                    bestIds = cand;\n                }\n            }\n            if (bestIds.empty()) {\n                plan.cost = INF64;\n                return plan;\n            }\n\n            Block b;\n            b.pickup = true;\n            b.ids = move(bestIds);\n            b.order = move(bestBS.order);\n            b.moveCost = bestBS.moveCost;\n            b.endPt = bestBS.endPt;\n\n            plan.blocks.push_back(b);\n            plan.cost += b.moveCost;\n            remove_ids_from_rem(remS, b.ids);\n            cur = b.endPt;\n            load += need;\n        }\n\n        if (load > 0) {\n            int need = load;\n            auto sets = generate_candidate_sets(remT, dst, cur, need);\n\n            BlockSolution bestBS;\n            vector<int> bestIds;\n            for (auto& cand : sets) {\n                auto bs = solve_block_fast(cur, cand, false, remS, remT, load - need, h, biasScale);\n                if (bs.score < bestBS.score || (bs.score == bestBS.score && bs.moveCost < bestBS.moveCost)) {\n                    bestBS = move(bs);\n                    bestIds = cand;\n                }\n            }\n            if (bestIds.empty()) {\n                plan.cost = INF64;\n                return plan;\n            }\n\n            Block b;\n            b.pickup = false;\n            b.ids = move(bestIds);\n            b.order = move(bestBS.order);\n            b.moveCost = bestBS.moveCost;\n            b.endPt = bestBS.endPt;\n\n            plan.blocks.push_back(b);\n            plan.cost += b.moveCost;\n            remove_ids_from_rem(remT, b.ids);\n            cur = b.endPt;\n            load -= need;\n        }\n    }\n\n    return plan;\n}\n\nPlan make_adaptive_plan(int h, int startIdx, int biasScale, int switchPenalty, const Timer& timer, double limit_ms) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.cost = 2;\n    plan.name = \"adaptive:\" + to_string(h) + \":\" + to_string(startIdx) + \":\" + to_string(biasScale) + \":\" + to_string(switchPenalty);\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    Pt cur = src[startIdx];\n    int load = 1;\n    int prevType = 1;\n\n    while (!remS.empty() || load > 0) {\n        if (timer.over(limit_ms)) {\n            plan.cost = INF64;\n            return plan;\n        }\n\n        long long bestOptionScore = INF64;\n        long long bestMoveCost = INF64;\n        Block bestBlock;\n        int bestDeltaLoad = 0;\n        int bestType = -1;\n\n        if (load < h && !remS.empty()) {\n            int maxAdd = min(h - load, (int)remS.size());\n            vector<int> sizes = {1};\n            if (maxAdd >= 2) sizes.push_back(2);\n            if (maxAdd >= 3) sizes.push_back(3);\n            if (maxAdd >= 4) sizes.push_back((maxAdd + 1) / 2);\n            if (maxAdd >= 4) sizes.push_back(maxAdd);\n            sort(sizes.begin(), sizes.end());\n            sizes.erase(unique(sizes.begin(), sizes.end()), sizes.end());\n\n            for (int k : sizes) {\n                auto sets = generate_candidate_sets(remS, src, cur, k);\n                for (auto& cand : sets) {\n                    auto bs = solve_block_fast(cur, cand, true, remS, remT, load + k, h, biasScale);\n                    long long score = bs.score + (prevType != 1 ? switchPenalty : 0);\n                    if (score < bestOptionScore || (score == bestOptionScore && bs.moveCost < bestMoveCost)) {\n                        bestOptionScore = score;\n                        bestMoveCost = bs.moveCost;\n                        bestType = 1;\n                        bestDeltaLoad = +k;\n                        bestBlock.pickup = true;\n                        bestBlock.ids = cand;\n                        bestBlock.order = move(bs.order);\n                        bestBlock.moveCost = bs.moveCost;\n                        bestBlock.endPt = bs.endPt;\n                    }\n                }\n            }\n        }\n\n        if (load > 0) {\n            int maxDrop = load;\n            vector<int> sizes = {1};\n            if (maxDrop >= 2) sizes.push_back(2);\n            if (maxDrop >= 3) sizes.push_back(3);\n            if (maxDrop >= 4) sizes.push_back((maxDrop + 1) / 2);\n            if (maxDrop >= 4) sizes.push_back(maxDrop);\n            sort(sizes.begin(), sizes.end());\n            sizes.erase(unique(sizes.begin(), sizes.end()), sizes.end());\n\n            for (int k : sizes) {\n                auto sets = generate_candidate_sets(remT, dst, cur, k);\n                for (auto& cand : sets) {\n                    auto bs = solve_block_fast(cur, cand, false, remS, remT, load - k, h, biasScale);\n                    long long score = bs.score + (prevType != 0 ? switchPenalty : 0);\n                    if (score < bestOptionScore || (score == bestOptionScore && bs.moveCost < bestMoveCost)) {\n                        bestOptionScore = score;\n                        bestMoveCost = bs.moveCost;\n                        bestType = 0;\n                        bestDeltaLoad = -k;\n                        bestBlock.pickup = false;\n                        bestBlock.ids = cand;\n                        bestBlock.order = move(bs.order);\n                        bestBlock.moveCost = bs.moveCost;\n                        bestBlock.endPt = bs.endPt;\n                    }\n                }\n            }\n        }\n\n        if (bestType == -1) {\n            plan.cost = INF64;\n            return plan;\n        }\n\n        plan.blocks.push_back(bestBlock);\n        plan.cost += bestBlock.moveCost;\n        cur = bestBlock.endPt;\n        if (bestType == 1) remove_ids_from_rem(remS, bestBlock.ids);\n        else remove_ids_from_rem(remT, bestBlock.ids);\n        load += bestDeltaLoad;\n        prevType = bestType;\n    }\n\n    return plan;\n}\n\nint path_gain_dp(const Pt& a, const Pt& b, bool pickup, const vector<char>& remainMark) {\n    static int dp[31][31];\n\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) dp[i][j] = -INF;\n    }\n    dp[0][0] = 0;\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && remainMark[idx]) add = 1;\n\n            int best = -INF;\n            if (i > 0) best = max(best, dp[i - 1][j]);\n            if (j > 0) best = max(best, dp[i][j - 1]);\n            dp[i][j] = best + add;\n        }\n    }\n    return dp[dx][dy];\n}\n\nvector<char> reconstruct_best_path(const Pt& a, const Pt& b, bool pickup, const vector<char>& remainMark) {\n    static int dp[31][31];\n    static char par[31][31];\n\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            dp[i][j] = -INF;\n            par[i][j] = '?';\n        }\n    }\n    dp[0][0] = 0;\n    par[0][0] = '.';\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && remainMark[idx]) add = 1;\n\n            int best = -INF;\n            char bp = '?';\n            if (i > 0) {\n                int cand = dp[i - 1][j] + add;\n                if (cand > best) {\n                    best = cand;\n                    bp = 'V';\n                }\n            }\n            if (j > 0) {\n                int cand = dp[i][j - 1] + add;\n                if (cand > best) {\n                    best = cand;\n                    bp = 'H';\n                }\n            }\n            dp[i][j] = best;\n            par[i][j] = bp;\n        }\n    }\n\n    vector<char> rev;\n    int i = dx, j = dy;\n    while (!(i == 0 && j == 0)) {\n        if (par[i][j] == 'V') {\n            rev.push_back(sx == 1 ? 'D' : 'U');\n            --i;\n        } else {\n            rev.push_back(sy == 1 ? 'R' : 'L');\n            --j;\n        }\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nExecResult execute_plan_pathaware(const Plan& plan, bool buildOps, int Vp, int leafCount) {\n    ExecResult res;\n    if (buildOps) res.ops.clear();\n\n    auto make_cmd = [&]() -> string {\n        return string(2 * Vp, '.');\n    };\n\n    Pt cur = src[plan.startIdx];\n    long long steps = 0;\n    int load = 1;\n\n    vector<int> holding(leafCount, 0);\n    if (leafCount > 0) holding[0] = 1;\n\n    auto emit_turn = [&](char mv, bool doAction, bool pickup) {\n        steps++;\n        if (!buildOps) {\n            if (doAction) {\n                if (pickup) load++;\n                else load--;\n            }\n            return;\n        }\n\n        string cmd = make_cmd();\n        cmd[0] = mv;\n\n        if (doAction) {\n            int chosen = -1;\n            if (pickup) {\n                for (int i = 0; i < leafCount; i++) {\n                    if (!holding[i]) {\n                        chosen = i;\n                        holding[i] = 1;\n                        break;\n                    }\n                }\n                if (chosen < 0) chosen = 0;\n                load++;\n            } else {\n                for (int i = 0; i < leafCount; i++) {\n                    if (holding[i]) {\n                        chosen = i;\n                        holding[i] = 0;\n                        break;\n                    }\n                }\n                if (chosen < 0) chosen = 0;\n                load--;\n            }\n            int vertex = 2 + chosen;\n            cmd[Vp + vertex] = 'P';\n        }\n\n        res.ops.push_back(move(cmd));\n    };\n\n    if (buildOps) {\n        string cmd0 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd0[u] = 'R';\n        res.ops.push_back(cmd0);\n\n        string cmd1 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd1[u] = 'R';\n        cmd1[Vp + 2] = 'P';\n        res.ops.push_back(cmd1);\n    }\n    steps += 2;\n\n    for (const auto& block : plan.blocks) {\n        vector<char> remainMark(Qm, 0);\n        int remCnt = 0;\n        for (int id : block.ids) {\n            remainMark[id] = 1;\n            remCnt++;\n        }\n\n        while (remCnt > 0) {\n            int idxCur = block.pickup ? srcIdAt[cur.x][cur.y] : dstIdAt[cur.x][cur.y];\n            if (idxCur != -1 && remainMark[idxCur]) {\n                remainMark[idxCur] = 0;\n                remCnt--;\n                emit_turn('.', true, block.pickup);\n                continue;\n            }\n\n            int minx = N, miny = N, maxx = -1, maxy = -1;\n            vector<int> remIds;\n            remIds.reserve(remCnt);\n            for (int id : block.ids) if (remainMark[id]) {\n                remIds.push_back(id);\n                const Pt& p = block.pickup ? src[id] : dst[id];\n                minx = min(minx, p.x);\n                miny = min(miny, p.y);\n                maxx = max(maxx, p.x);\n                maxy = max(maxy, p.y);\n            }\n\n            int bestGain = -1;\n            int bestDist = INF;\n            int bestIsRemain = -1;\n            Pt bestPt{-1, -1};\n\n            auto consider = [&](const Pt& p, int isRemain) {\n                if (p.x == cur.x && p.y == cur.y) return;\n                int g = path_gain_dp(cur, p, block.pickup, remainMark);\n                int d = manhattan(cur, p);\n                if (g > bestGain ||\n                    (g == bestGain && (d < bestDist ||\n                     (d == bestDist && isRemain > bestIsRemain)))) {\n                    bestGain = g;\n                    bestDist = d;\n                    bestIsRemain = isRemain;\n                    bestPt = p;\n                }\n            };\n\n            for (int id : remIds) {\n                consider(block.pickup ? src[id] : dst[id], 1);\n            }\n\n            if (remCnt >= 3) {\n                vector<Pt> extras = {\n                    {minx, miny}, {minx, maxy}, {maxx, miny}, {maxx, maxy}\n                };\n                sort(extras.begin(), extras.end(), [](const Pt& a, const Pt& b) {\n                    if (a.x != b.x) return a.x < b.x;\n                    return a.y < b.y;\n                });\n                extras.erase(unique(extras.begin(), extras.end(), [](const Pt& a, const Pt& b) {\n                    return a.x == b.x && a.y == b.y;\n                }), extras.end());\n\n                for (const auto& p : extras) {\n                    consider(p, 0);\n                }\n            }\n\n            if (bestGain <= 0) {\n                int bestId = -1;\n                int d0 = INF;\n                for (int id : remIds) {\n                    Pt p = block.pickup ? src[id] : dst[id];\n                    int d = manhattan(cur, p);\n                    if (d < d0) d0 = d, bestId = id;\n                }\n                bestPt = block.pickup ? src[bestId] : dst[bestId];\n            }\n\n            vector<char> moves = reconstruct_best_path(cur, bestPt, block.pickup, remainMark);\n            if (moves.empty()) {\n                int bestId = -1;\n                int d0 = INF;\n                for (int id : remIds) {\n                    Pt p = block.pickup ? src[id] : dst[id];\n                    int d = manhattan(cur, p);\n                    if (d < d0 && !(p.x == cur.x && p.y == cur.y)) {\n                        d0 = d;\n                        bestId = id;\n                    }\n                }\n                if (bestId == -1) {\n                    int anyId = remIds[0];\n                    remainMark[anyId] = 0;\n                    remCnt--;\n                    emit_turn('.', true, block.pickup);\n                    continue;\n                }\n                bestPt = block.pickup ? src[bestId] : dst[bestId];\n                moves = reconstruct_best_path(cur, bestPt, block.pickup, remainMark);\n            }\n\n            for (char mv : moves) {\n                if (mv == 'U') cur.x--;\n                else if (mv == 'D') cur.x++;\n                else if (mv == 'L') cur.y--;\n                else if (mv == 'R') cur.y++;\n\n                bool act = false;\n                int idx = block.pickup ? srcIdAt[cur.x][cur.y] : dstIdAt[cur.x][cur.y];\n                if (idx != -1 && remainMark[idx]) {\n                    remainMark[idx] = 0;\n                    remCnt--;\n                    act = true;\n                }\n                emit_turn(mv, act, block.pickup);\n            }\n        }\n    }\n\n    if (load != 0) {\n        res.cost = INF64;\n        return res;\n    }\n    res.cost = steps;\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TIME_LIMIT_MS = 2300.0;\n\n    cin >> N >> M >> Vcap;\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    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (s[i][j] == '1' && t[i][j] == '0') src.push_back({i, j});\n            else if (s[i][j] == '0' && t[i][j] == '1') dst.push_back({i, j});\n        }\n    }\n    Qm = (int)src.size();\n\n    const int Vp = Vcap;\n    const int leafCount = Vp - 2;\n\n    auto output_tree = [&](int root_x, int root_y) {\n        cout << Vp << '\\n';\n        cout << 0 << ' ' << 1 << '\\n';\n        for (int u = 2; u < Vp; u++) cout << 1 << ' ' << 1 << '\\n';\n        cout << root_x << ' ' << root_y << '\\n';\n    };\n\n    if (Qm == 0) {\n        output_tree(0, 0);\n        return 0;\n    }\n\n    SS.assign(Qm, vector<unsigned char>(Qm));\n    ST.assign(Qm, vector<unsigned char>(Qm));\n    TS.assign(Qm, vector<unsigned char>(Qm));\n    TT.assign(Qm, vector<unsigned char>(Qm));\n    for (int i = 0; i < Qm; i++) {\n        for (int j = 0; j < Qm; j++) {\n            SS[i][j] = (unsigned char)manhattan(src[i], src[j]);\n            ST[i][j] = (unsigned char)manhattan(src[i], dst[j]);\n            TS[i][j] = (unsigned char)manhattan(dst[i], src[j]);\n            TT[i][j] = (unsigned char)manhattan(dst[i], dst[j]);\n        }\n    }\n\n    srcIdAt.assign(N, vector<int>(N, -1));\n    dstIdAt.assign(N, vector<int>(N, -1));\n    for (int i = 0; i < Qm; i++) {\n        srcIdAt[src[i].x][src[i].y] = i;\n        dstIdAt[dst[i].x][dst[i].y] = i;\n    }\n\n    vector<int> startCandidates = make_start_candidates();\n    int maxH = min(leafCount, Qm);\n\n    vector<tuple<long long,int,int>> roughList;\n    roughList.reserve((int)startCandidates.size() * maxH);\n    for (int h = 1; h <= maxH; h++) {\n        for (int st : startCandidates) {\n            roughList.emplace_back(rough_simulate(h, st), h, st);\n        }\n    }\n    sort(roughList.begin(), roughList.end());\n\n    vector<pair<int,int>> seedPairs;\n    set<pair<int,int>> usedSeed;\n\n    auto add_seed = [&](int h, int st) {\n        if (usedSeed.insert({h, st}).second) seedPairs.push_back({h, st});\n    };\n\n    for (int i = 0; i < min(5, (int)roughList.size()); i++) {\n        auto [c, h, st] = roughList[i];\n        add_seed(h, st);\n    }\n    for (int h = 1; h <= maxH && (int)seedPairs.size() < 8; h++) {\n        long long best = INF64;\n        int bst = -1;\n        for (auto &[c, hh, st] : roughList) {\n            if (hh == h && c < best) {\n                best = c;\n                bst = st;\n            }\n        }\n        if (bst != -1) add_seed(h, bst);\n    }\n    if (seedPairs.empty()) {\n        auto [c, h, st] = roughList[0];\n        seedPairs.push_back({h, st});\n    }\n\n    auto [bestH0, bestSt0] = seedPairs[0];\n    Plan bestPlan = make_fill_plan(bestH0, bestSt0, 0, timer, TIME_LIMIT_MS);\n    if (bestPlan.cost >= INF64 / 2) {\n        bestPlan = make_fill_plan(bestH0, bestSt0, 0, timer, 1e18);\n    }\n    long long bestActual = execute_plan_pathaware(bestPlan, false, Vp, leafCount).cost;\n\n    for (int i = 0; i < (int)seedPairs.size(); i++) {\n        if (timer.over(TIME_LIMIT_MS)) break;\n        auto [h, st] = seedPairs[i];\n\n        {\n            Plan p = make_fill_plan(h, st, 1, timer, TIME_LIMIT_MS);\n            if (p.cost < INF64 / 2) {\n                long long actual = execute_plan_pathaware(p, false, Vp, leafCount).cost;\n                if (actual < bestActual) {\n                    bestActual = actual;\n                    bestPlan = move(p);\n                }\n            }\n        }\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        if (i < 3) {\n            Plan p = make_adaptive_plan(h, st, 1, 2, timer, TIME_LIMIT_MS);\n            if (p.cost < INF64 / 2) {\n                long long actual = execute_plan_pathaware(p, false, Vp, leafCount).cost;\n                if (actual < bestActual) {\n                    bestActual = actual;\n                    bestPlan = move(p);\n                }\n            }\n        }\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        if (i < 2) {\n            Plan p = make_fill_plan(h, st, 2, timer, TIME_LIMIT_MS);\n            if (p.cost < INF64 / 2) {\n                long long actual = execute_plan_pathaware(p, false, Vp, leafCount).cost;\n                if (actual < bestActual) {\n                    bestActual = actual;\n                    bestPlan = move(p);\n                }\n            }\n        }\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        if (i < 2) {\n            Plan p = make_adaptive_plan(h, st, 0, 0, timer, TIME_LIMIT_MS);\n            if (p.cost < INF64 / 2) {\n                long long actual = execute_plan_pathaware(p, false, Vp, leafCount).cost;\n                if (actual < bestActual) {\n                    bestActual = actual;\n                    bestPlan = move(p);\n                }\n            }\n        }\n    }\n\n    ExecResult bestRes = execute_plan_pathaware(bestPlan, true, Vp, leafCount);\n\n    output_tree(src[bestPlan.startIdx].x, src[bestPlan.startIdx].y);\n    for (auto& cmd : bestRes.ops) cout << cmd << '\\n';\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic constexpr int COORD_MAX = 100000;\nstatic constexpr int ENC_SHIFT = 17;\nstatic constexpr int ENC_MASK = (1 << ENC_SHIFT) - 1;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct GridData {\n    int G, sx, sy;\n    int W, H;\n    vector<int> xs, ys;\n    vector<int> w;\n};\n\nstruct Component {\n    vector<int> cells;\n    int prize = 0;\n};\n\nstruct ComponentsResult {\n    vector<Component> comps;\n    vector<int> compId;\n    int bestCid = -1;\n    int positiveCount = 0;\n};\n\nstruct Candidate {\n    vector<Pt> poly;\n    long long approx = 0;\n    int perim = 0;\n    int minx = 0, maxx = 0, miny = 0, maxy = 0;\n    uint64_t hash = 0;\n};\n\nstruct FishEnv {\n    vector<Pt> pts;\n    vector<int> sgn;\n    vector<int> ordY;\n    vector<vector<int>> byX, byY;\n};\n\nstatic inline long long enc_xy(int x, int y) {\n    return (static_cast<long long>(x) << ENC_SHIFT) | y;\n}\n\nstatic inline Pt dec_xy(long long v) {\n    return Pt{static_cast<int>(v >> ENC_SHIFT), static_cast<int>(v & ENC_MASK)};\n}\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nvector<int> create_bounds(int G, int shift) {\n    vector<int> res;\n    res.push_back(0);\n    int cur = 0;\n    if (shift > 0) {\n        res.push_back(shift);\n        cur = shift;\n    }\n    while (cur < COORD_MAX) {\n        cur = min(COORD_MAX, cur + G);\n        if (cur > res.back()) res.push_back(cur);\n    }\n    return res;\n}\n\nint coord_to_index(int v, int G, int shift, int cells) {\n    if (v == COORD_MAX) return cells - 1;\n    if (shift > 0 && v < shift) return 0;\n    int idx;\n    if (shift == 0) idx = v / G;\n    else idx = 1 + (v - shift) / G;\n    if (idx < 0) idx = 0;\n    if (idx >= cells) idx = cells - 1;\n    return idx;\n}\n\nGridData build_grid(const vector<Pt>& macks, const vector<Pt>& sards, int G, int sx, int sy) {\n    GridData gd;\n    gd.G = G; gd.sx = sx; gd.sy = sy;\n    gd.xs = create_bounds(G, sx);\n    gd.ys = create_bounds(G, sy);\n    gd.W = (int)gd.xs.size() - 1;\n    gd.H = (int)gd.ys.size() - 1;\n    gd.w.assign(gd.W * gd.H, 0);\n\n    auto id = [&](int x, int y) { return y * gd.W + x; };\n\n    for (const auto& p : macks) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]++;\n    }\n    for (const auto& p : sards) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]--;\n    }\n    return gd;\n}\n\nlong long region_sum(const vector<char>& occ, const vector<int>& w) {\n    long long s = 0;\n    for (int i = 0; i < (int)occ.size(); i++) if (occ[i]) s += w[i];\n    return s;\n}\n\nvector<char> best_rectangle_region(const GridData& gd) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    long long best = LLONG_MIN;\n    int bestL = -1, bestR = -1, bestB = -1, bestT = -1;\n\n    vector<long long> tmp(H);\n    for (int L = 0; L < W; L++) {\n        fill(tmp.begin(), tmp.end(), 0);\n        for (int R = L; R < W; R++) {\n            for (int y = 0; y < H; y++) tmp[y] += gd.w[id(R, y)];\n            long long cur = 0;\n            int st = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = tmp[y];\n                    st = y;\n                } else {\n                    cur += tmp[y];\n                }\n                if (cur > best) {\n                    best = cur;\n                    bestL = L; bestR = R; bestB = st; bestT = y;\n                }\n            }\n        }\n    }\n\n    vector<char> occ(W * H, 0);\n    if (best <= 0 || bestL < 0) return occ;\n    for (int y = bestB; y <= bestT; y++) {\n        for (int x = bestL; x <= bestR; x++) occ[id(x, y)] = 1;\n    }\n    return occ;\n}\n\nvector<char> graph_cut_select(const GridData& gd, int lambda) {\n    int W = gd.W, H = gd.H;\n    int V = W * H;\n    int S = V, T = V + 1;\n    mf_graph<long long> mf(V + 2);\n\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int ww = gd.w[v];\n            if (ww >= 0) mf.add_edge(S, v, ww);\n            else mf.add_edge(v, T, -ww);\n\n            int border = 0;\n            if (x == 0) border++;\n            if (x == W - 1) border++;\n            if (y == 0) border++;\n            if (y == H - 1) border++;\n            if (border) mf.add_edge(v, T, 1LL * lambda * border);\n\n            if (x + 1 < W) {\n                int u = id(x + 1, y);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n            if (y + 1 < H) {\n                int u = id(x, y + 1);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n        }\n    }\n\n    mf.flow(S, T);\n    auto cut = mf.min_cut(S);\n    vector<char> sel(V, 0);\n    for (int i = 0; i < V; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nComponentsResult get_components(const vector<char>& sel, const vector<int>& w, int W, int H) {\n    ComponentsResult res;\n    int V = W * H;\n    res.compId.assign(V, -1);\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    int cid = 0;\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int s = id(x, y);\n            if (!sel[s] || res.compId[s] != -1) continue;\n\n            queue<int> q;\n            q.push(s);\n            res.compId[s] = cid;\n            Component comp;\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                comp.cells.push_back(v);\n                comp.prize += w[v];\n\n                int vx = v % W, vy = v / W;\n                static const int dx[4] = {1, -1, 0, 0};\n                static const int dy[4] = {0, 0, 1, -1};\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = vx + dx[dir], ny = vy + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (!sel[u] || res.compId[u] != -1) continue;\n                    res.compId[u] = cid;\n                    q.push(u);\n                }\n            }\n\n            res.comps.push_back(std::move(comp));\n            cid++;\n        }\n    }\n\n    int bestPrize = INT_MIN;\n    for (int i = 0; i < (int)res.comps.size(); i++) {\n        if (res.comps[i].prize > 0) {\n            res.positiveCount++;\n            if (res.comps[i].prize > bestPrize) {\n                bestPrize = res.comps[i].prize;\n                res.bestCid = i;\n            }\n        }\n    }\n    return res;\n}\n\nvoid fill_holes(vector<char>& occ, int W, int H) {\n    int PW = W + 2, PH = H + 2;\n    vector<char> vis(PW * PH, 0);\n\n    auto pid = [&](int x, int y) { return y * PW + x; };\n    auto blocked = [&](int x, int y) -> bool {\n        if (x == 0 || x == W + 1 || y == 0 || y == H + 1) return false;\n        return occ[(y - 1) * W + (x - 1)];\n    };\n\n    queue<int> q;\n    q.push(pid(0, 0));\n    vis[pid(0, 0)] = 1;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % PW, y = v / PW;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (nx < 0 || nx >= PW || ny < 0 || ny >= PH) continue;\n            int u = pid(nx, ny);\n            if (vis[u] || blocked(nx, ny)) continue;\n            vis[u] = 1;\n            q.push(u);\n        }\n    }\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = y * W + x;\n            if (!occ[v] && !vis[pid(x + 1, y + 1)]) occ[v] = 1;\n        }\n    }\n}\n\nint count_occ_neighbors(const vector<char>& occ, int v, int W, int H) {\n    int x = v % W, y = v / W;\n    int k = 0;\n    if (x > 0 && occ[v - 1]) k++;\n    if (x + 1 < W && occ[v + 1]) k++;\n    if (y > 0 && occ[v - W]) k++;\n    if (y + 1 < H && occ[v + W]) k++;\n    return k;\n}\n\nbool is_boundary_cell(const vector<char>& occ, int v, int W, int H) {\n    if (!occ[v]) return false;\n    int x = v % W, y = v / W;\n    if (x == 0 || x == W - 1 || y == 0 || y == H - 1) return true;\n    if (!occ[v - 1] || !occ[v + 1] || !occ[v - W] || !occ[v + W]) return true;\n    return false;\n}\n\nbool can_remove_connected(const vector<char>& occ, int rem, int W, int H, int occCount) {\n    if (occCount <= 1) return false;\n    int k = count_occ_neighbors(occ, rem, W, H);\n    if (k <= 1) return true;\n\n    int start = -1;\n    for (int i = 0; i < (int)occ.size(); i++) {\n        if (i != rem && occ[i]) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return false;\n\n    vector<char> vis(occ.size(), 0);\n    queue<int> q;\n    q.push(start);\n    vis[start] = 1;\n    int seen = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (!inside(nx, ny)) continue;\n            int u = id(nx, ny);\n            if (u == rem || !occ[u] || vis[u]) continue;\n            vis[u] = 1;\n            seen++;\n            q.push(u);\n        }\n    }\n    return seen == occCount - 1;\n}\n\nvoid local_hill_climb(vector<char>& occ, const vector<int>& w, int W, int H, int beta) {\n    auto id = [&](int x, int y) { return y * W + x; };\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n\n    int occCount = 0;\n    for (char c : occ) if (c) occCount++;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    for (int pass = 0; pass < 3; pass++) {\n        bool changed = false;\n\n        {\n            vector<pair<int,int>> cand;\n            for (int v = 0; v < W * H; v++) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                bool adj = false;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) {\n                        adj = true;\n                        k++;\n                    }\n                }\n                if (!adj) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 60) cand.resize(60);\n\n            for (auto [ng, v] : cand) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) k++;\n                }\n                if (k == 0) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) {\n                    occ[v] = 1;\n                    occCount++;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        {\n            vector<pair<int,int>> cand;\n            for (int v = 0; v < W * H; v++) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 60) cand.resize(60);\n\n            for (auto [ng, v] : cand) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain <= 0) continue;\n                if (can_remove_connected(occ, v, W, H, occCount)) {\n                    occ[v] = 0;\n                    occCount--;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid refine_occ(vector<char>& occ, const vector<int>& w, int W, int H) {\n    fill_holes(occ, W, H);\n    local_hill_climb(occ, w, W, H, 1);\n    local_hill_climb(occ, w, W, H, 2);\n    fill_holes(occ, W, H);\n}\n\nvector<int> top_positive_components(const ComponentsResult& cr, int K) {\n    vector<int> ids;\n    for (int i = 0; i < (int)cr.comps.size(); i++) {\n        if (cr.comps[i].prize > 0) ids.push_back(i);\n    }\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (cr.comps[a].prize != cr.comps[b].prize) return cr.comps[a].prize > cr.comps[b].prize;\n        return cr.comps[a].cells.size() < cr.comps[b].cells.size();\n    });\n    if ((int)ids.size() > K) ids.resize(K);\n    return ids;\n}\n\nvector<char> greedy_connect_mode(\n    const vector<char>& sel,\n    const ComponentsResult& cr,\n    const vector<int>& w,\n    int W, int H,\n    int seedCid,\n    int mode\n) {\n    int V = W * H;\n    vector<char> occ(V, 0);\n    if (seedCid < 0 || seedCid >= (int)cr.comps.size()) return occ;\n    if (cr.comps[seedCid].prize <= 0) return occ;\n\n    int C = (int)cr.comps.size();\n    vector<char> goodComp(C, 0);\n    for (int i = 0; i < C; i++) goodComp[i] = (cr.comps[i].prize > 0);\n\n    vector<char> added(C, 0);\n    for (int v : cr.comps[seedCid].cells) occ[v] = 1;\n    added[seedCid] = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    auto is_good_sel = [&](int v) -> bool {\n        if (!sel[v]) return false;\n        int cid = cr.compId[v];\n        return cid >= 0 && goodComp[cid];\n    };\n\n    int gainMul = (mode == 0 ? 8 : 12);\n\n    auto enter_cost = [&](int v) -> int {\n        if (occ[v]) return 0;\n        if (is_good_sel(v)) return 0;\n        int ww = w[v];\n        if (mode == 0) {\n            if (ww >= 2) return 0;\n            if (ww == 1) return 1;\n            if (ww == 0) return 4;\n            return 4 + 6 * (-ww);\n        } else {\n            if (ww >= 1) return 0;\n            if (ww == 0) return 2;\n            return 2 + 4 * (-ww);\n        }\n    };\n\n    for (int iter = 0; iter < 12; iter++) {\n        const int INF = 1e9;\n        vector<int> dist(V, INF), parent(V, -1);\n        priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n\n        for (int v = 0; v < V; v++) {\n            if (occ[v]) {\n                dist[v] = 0;\n                pq.push({0, v});\n            }\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            int x = v % W, y = v / W;\n            static const int dx[4] = {1, -1, 0, 0};\n            static const int dy[4] = {0, 0, 1, -1};\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!inside(nx, ny)) continue;\n                int u = id(nx, ny);\n                int nd = d + enter_cost(u);\n                if (nd < dist[u]) {\n                    dist[u] = nd;\n                    parent[u] = v;\n                    pq.push({nd, u});\n                }\n            }\n        }\n\n        long long bestGain = 0;\n        int chooseCid = -1;\n        int chooseCell = -1;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!goodComp[cid] || added[cid]) continue;\n            int bestDist = INF;\n            int bestCell = -1;\n            for (int v : cr.comps[cid].cells) {\n                if (dist[v] < bestDist) {\n                    bestDist = dist[v];\n                    bestCell = v;\n                }\n            }\n            if (bestCell == -1) continue;\n            long long gain = 1LL * gainMul * cr.comps[cid].prize - bestDist;\n            if (gain > bestGain) {\n                bestGain = gain;\n                chooseCid = cid;\n                chooseCell = bestCell;\n            }\n        }\n\n        if (chooseCid == -1) break;\n\n        vector<char> touched(C, 0);\n        int v = chooseCell;\n        while (v != -1 && !occ[v]) {\n            occ[v] = 1;\n            if (is_good_sel(v)) touched[cr.compId[v]] = 1;\n            v = parent[v];\n        }\n        touched[chooseCid] = 1;\n\n        bool anyNew = false;\n        for (int cid = 0; cid < C; cid++) {\n            if (!touched[cid] || added[cid]) continue;\n            added[cid] = 1;\n            anyNew = true;\n            for (int u : cr.comps[cid].cells) occ[u] = 1;\n        }\n        if (!anyNew) break;\n    }\n\n    return occ;\n}\n\nvector<char> bbox_occ_from_cells(const vector<int>& cells, int W, int H) {\n    vector<char> occ(W * H, 0);\n    if (cells.empty()) return occ;\n    int minx = W, maxx = -1, miny = H, maxy = -1;\n    for (int v : cells) {\n        int x = v % W, y = v / W;\n        minx = min(minx, x);\n        maxx = max(maxx, x);\n        miny = min(miny, y);\n        maxy = max(maxy, y);\n    }\n    for (int y = miny; y <= maxy; y++) {\n        for (int x = minx; x <= maxx; x++) occ[y * W + x] = 1;\n    }\n    return occ;\n}\n\nvector<Pt> build_polygon(const GridData& gd, const vector<char>& occ) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    unordered_map<long long, long long> nxt;\n    nxt.reserve((size_t)occ.size() * 3 + 16);\n    bool bad = false;\n    long long start = -1;\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) {\n        long long a = enc_xy(x1, y1);\n        long long b = enc_xy(x2, y2);\n        auto it = nxt.find(a);\n        if (it != nxt.end() && it->second != b) bad = true;\n        nxt[a] = b;\n        if (start == -1 || a < start) start = a;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            if (!occ[v]) continue;\n            int x0 = gd.xs[x], x1 = gd.xs[x + 1];\n            int y0 = gd.ys[y], y1 = gd.ys[y + 1];\n\n            if (y == 0 || !occ[id(x, y - 1)]) add_edge(x0, y0, x1, y0);\n            if (x == W - 1 || !occ[id(x + 1, y)]) add_edge(x1, y0, x1, y1);\n            if (y == H - 1 || !occ[id(x, y + 1)]) add_edge(x1, y1, x0, y1);\n            if (x == 0 || !occ[id(x - 1, y)]) add_edge(x0, y1, x0, y0);\n        }\n    }\n\n    if (bad || start == -1) return {};\n\n    vector<Pt> poly;\n    long long cur = start;\n    int steps = 0;\n\n    while (true) {\n        poly.push_back(dec_xy(cur));\n        auto it = nxt.find(cur);\n        if (it == nxt.end()) return {};\n        cur = it->second;\n        steps++;\n        if (cur == start) break;\n        if (steps > (int)nxt.size() + 5) return {};\n    }\n\n    if (steps != (int)nxt.size()) return {};\n\n    auto collinear = [&](const Pt& a, const Pt& b, const Pt& c) {\n        return (a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y);\n    };\n\n    bool changed = true;\n    while (changed && (int)poly.size() > 4) {\n        changed = false;\n        vector<Pt> np;\n        int m = (int)poly.size();\n        np.reserve(m);\n        for (int i = 0; i < m; i++) {\n            const Pt& prev = poly[(i - 1 + m) % m];\n            const Pt& curp = poly[i];\n            const Pt& nextp = poly[(i + 1) % m];\n            if (collinear(prev, curp, nextp)) changed = true;\n            else np.push_back(curp);\n        }\n        poly.swap(np);\n    }\n\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return {};\n\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        long long e = enc_xy(poly[i].x, poly[i].y);\n        if (!seen.insert(e).second) return {};\n        perim += manhattan(poly[i], poly[(i + 1) % poly.size()]);\n    }\n    if (perim > 400000) return {};\n\n    return poly;\n}\n\nbool basic_valid_poly(const vector<Pt>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        const auto& a = poly[i];\n        const auto& b = poly[(i + 1) % poly.size()];\n        if (a.x != b.x && a.y != b.y) return false;\n        if (a.x == b.x && a.y == b.y) return false;\n        if (a.x < 0 || a.x > COORD_MAX || a.y < 0 || a.y > COORD_MAX) return false;\n        long long e = enc_xy(a.x, a.y);\n        if (!seen.insert(e).second) return false;\n        perim += manhattan(a, b);\n    }\n    return perim <= 400000;\n}\n\nuint64_t hash_poly(const vector<Pt>& poly) {\n    uint64_t h = 1469598103934665603ULL;\n    for (const auto& p : poly) {\n        uint64_t v = (uint64_t)p.x * 1000003ULL + (uint64_t)p.y + 0x9e3779b97f4a7c15ULL;\n        h ^= v;\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)poly.size() + 0x517cc1b727220a95ULL;\n    return h;\n}\n\nCandidate make_candidate(vector<Pt> poly, long long approx) {\n    Candidate c;\n    c.poly = std::move(poly);\n    c.approx = approx;\n    c.perim = 0;\n    c.minx = c.maxx = c.poly[0].x;\n    c.miny = c.maxy = c.poly[0].y;\n    for (int i = 0; i < (int)c.poly.size(); i++) {\n        c.perim += manhattan(c.poly[i], c.poly[(i + 1) % c.poly.size()]);\n        c.minx = min(c.minx, c.poly[i].x);\n        c.maxx = max(c.maxx, c.poly[i].x);\n        c.miny = min(c.miny, c.poly[i].y);\n        c.maxy = max(c.maxy, c.poly[i].y);\n    }\n    c.hash = hash_poly(c.poly);\n    return c;\n}\n\npair<vector<int>, bool> snap_axis_values(const vector<int>& vals, const vector<char>& has) {\n    vector<int> nv = vals;\n    bool changed = false;\n    int K = (int)vals.size();\n    for (int i = 0; i < K; i++) {\n        int L = (i == 0 ? 0 : nv[i - 1] + 1);\n        int R = (i + 1 < K ? vals[i + 1] - 1 : COORD_MAX);\n        if (L > R) {\n            nv[i] = vals[i];\n            continue;\n        }\n        if (!has[vals[i]]) {\n            nv[i] = vals[i];\n            continue;\n        }\n        int best = vals[i];\n        bool found = false;\n        int lim = max(vals[i] - L, R - vals[i]);\n        for (int d = 1; d <= lim; d++) {\n            int a = vals[i] - d;\n            if (a >= L && !has[a]) {\n                best = a;\n                found = true;\n                break;\n            }\n            int b = vals[i] + d;\n            if (b <= R && !has[b]) {\n                best = b;\n                found = true;\n                break;\n            }\n        }\n        if (found) {\n            nv[i] = best;\n            if (best != vals[i]) changed = true;\n        } else {\n            nv[i] = vals[i];\n        }\n    }\n    return {nv, changed};\n}\n\nvector<Pt> snap_poly_lines_mode(\n    const vector<Pt>& poly,\n    const vector<char>& hasX,\n    const vector<char>& hasY,\n    bool useX,\n    bool useY\n) {\n    if (!useX && !useY) return {};\n\n    vector<int> ux, uy;\n    ux.reserve(poly.size());\n    uy.reserve(poly.size());\n    for (auto& p : poly) {\n        ux.push_back(p.x);\n        uy.push_back(p.y);\n    }\n    sort(ux.begin(), ux.end());\n    ux.erase(unique(ux.begin(), ux.end()), ux.end());\n    sort(uy.begin(), uy.end());\n    uy.erase(unique(uy.begin(), uy.end()), uy.end());\n\n    vector<int> nx = ux, ny = uy;\n    bool cx = false, cy = false;\n    if (useX) {\n        auto r = snap_axis_values(ux, hasX);\n        nx = std::move(r.first);\n        cx = r.second;\n    }\n    if (useY) {\n        auto r = snap_axis_values(uy, hasY);\n        ny = std::move(r.first);\n        cy = r.second;\n    }\n    if (!cx && !cy) return {};\n\n    unordered_map<int,int> mx, my;\n    mx.reserve(ux.size() * 2 + 1);\n    my.reserve(uy.size() * 2 + 1);\n    for (int i = 0; i < (int)ux.size(); i++) mx[ux[i]] = nx[i];\n    for (int i = 0; i < (int)uy.size(); i++) my[uy[i]] = ny[i];\n\n    vector<Pt> out = poly;\n    for (auto& p : out) {\n        if (useX) p.x = mx[p.x];\n        if (useY) p.y = my[p.y];\n    }\n    if (!basic_valid_poly(out)) return {};\n    return out;\n}\n\nbool push_candidate(\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    vector<Pt> poly,\n    long long approx\n) {\n    if (poly.empty()) return false;\n    Candidate c = make_candidate(std::move(poly), approx);\n    if (!seenHash.insert(c.hash).second) return false;\n    cands.push_back(std::move(c));\n    return true;\n}\n\nvoid try_add_candidate(\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const GridData& gd,\n    const vector<char>& occ,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    long long approx = region_sum(occ, gd.w);\n    if (approx < 0) return;\n\n    auto poly = build_polygon(gd, occ);\n    if (poly.empty()) return;\n\n    push_candidate(cands, seenHash, poly, approx);\n\n    auto snapXY = snap_poly_lines_mode(poly, hasX, hasY, true, true);\n    if (!snapXY.empty()) push_candidate(cands, seenHash, std::move(snapXY), approx);\n\n    if ((int)poly.size() <= 120) {\n        auto snapX = snap_poly_lines_mode(poly, hasX, hasY, true, false);\n        if (!snapX.empty()) push_candidate(cands, seenHash, std::move(snapX), approx);\n        auto snapY = snap_poly_lines_mode(poly, hasX, hasY, false, true);\n        if (!snapY.empty()) push_candidate(cands, seenHash, std::move(snapY), approx);\n    }\n}\n\nstruct LazyFenwick {\n    int n = 0;\n    vector<int> bit;\n    vector<int> seen;\n    int stamp = 1;\n\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n        seen.assign(n + 1, 0);\n        stamp = 1;\n    }\n\n    void next() {\n        stamp++;\n        if (stamp == INT_MAX) {\n            fill(seen.begin(), seen.end(), 0);\n            stamp = 1;\n        }\n    }\n\n    inline void add_coord(int coord, int val) {\n        for (int i = coord + 1; i <= n; i += i & -i) {\n            if (seen[i] != stamp) {\n                seen[i] = stamp;\n                bit[i] = 0;\n            }\n            bit[i] += val;\n        }\n    }\n\n    inline int sum_exclusive(int x) const {\n        int s = 0;\n        for (int i = x; i > 0; i -= i & -i) {\n            if (seen[i] == stamp) s += bit[i];\n        }\n        return s;\n    }\n};\n\nstruct ExactScorer {\n    const FishEnv& env;\n    LazyFenwick fw;\n    vector<int> onStamp;\n    int curStamp = 1;\n    vector<pair<int,int>> addEv, remEv;\n\n    ExactScorer(const FishEnv& env_) : env(env_) {\n        fw.init(COORD_MAX + 1);\n        onStamp.assign(env.pts.size(), 0);\n    }\n\n    inline void next_stamp() {\n        curStamp++;\n        if (curStamp == INT_MAX) {\n            fill(onStamp.begin(), onStamp.end(), 0);\n            curStamp = 1;\n        }\n        fw.next();\n        addEv.clear();\n        remEv.clear();\n    }\n\n    int score(const Candidate& c) {\n        next_stamp();\n        addEv.reserve(c.poly.size());\n        remEv.reserve(c.poly.size());\n\n        int m = (int)c.poly.size();\n        for (int i = 0; i < m; i++) {\n            Pt a = c.poly[i];\n            Pt b = c.poly[(i + 1) % m];\n            if (a.x == b.x) {\n                int x = a.x;\n                int y1 = min(a.y, b.y), y2 = max(a.y, b.y);\n\n                for (int idx : env.byX[x]) {\n                    int py = env.pts[idx].y;\n                    if (y1 <= py && py <= y2) onStamp[idx] = curStamp;\n                }\n                if (y1 < y2) {\n                    addEv.push_back({y1, x});\n                    remEv.push_back({y2, x});\n                }\n            } else {\n                int y = a.y;\n                int x1 = min(a.x, b.x), x2 = max(a.x, b.x);\n\n                for (int idx : env.byY[y]) {\n                    int px = env.pts[idx].x;\n                    if (x1 <= px && px <= x2) onStamp[idx] = curStamp;\n                }\n            }\n        }\n\n        sort(addEv.begin(), addEv.end());\n        sort(remEv.begin(), remEv.end());\n\n        int ai = 0, ri = 0;\n        int diff = 0;\n\n        for (int idx : env.ordY) {\n            const Pt& p = env.pts[idx];\n            if (p.y < c.miny) continue;\n            if (p.y > c.maxy) break;\n\n            while (ri < (int)remEv.size() && remEv[ri].first <= p.y) {\n                fw.add_coord(remEv[ri].second, -1);\n                ri++;\n            }\n            while (ai < (int)addEv.size() && addEv[ai].first <= p.y) {\n                fw.add_coord(addEv[ai].second, +1);\n                ai++;\n            }\n\n            if (p.x < c.minx || p.x > c.maxx) continue;\n            bool inside = (onStamp[idx] == curStamp) ? true : ((fw.sum_exclusive(p.x) & 1) != 0);\n            if (inside) diff += env.sgn[idx];\n        }\n\n        return max(0, diff + 1);\n    }\n};\n\nvector<Pt> find_empty_square(const unordered_set<long long>& pts) {\n    auto has = [&](int x, int y) -> bool {\n        return pts.find(1LL * x * (COORD_MAX + 1) + y) != pts.end();\n    };\n    for (int x = 0; x <= 1000; x++) {\n        for (int y = 0; y <= 1000; y++) {\n            if (x + 1 > COORD_MAX || y + 1 > COORD_MAX) continue;\n            if (!has(x, y) && !has(x + 1, y) && !has(x, y + 1) && !has(x + 1, y + 1)) {\n                return {{x, y}, {x + 1, y}, {x + 1, y + 1}, {x, y + 1}};\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nvoid process_selection(\n    const GridData& gd,\n    const vector<char>& sel,\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    auto cr = get_components(sel, gd.w, gd.W, gd.H);\n    auto top = top_positive_components(cr, 3);\n    if (top.empty()) return;\n\n    for (int cid : top) {\n        vector<char> occ(gd.W * gd.H, 0);\n        for (int v : cr.comps[cid].cells) occ[v] = 1;\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n\n    int seeds = min(2, (int)top.size());\n    for (int i = 0; i < seeds; i++) {\n        int cid = top[i];\n        auto occ = greedy_connect_mode(sel, cr, gd.w, gd.W, gd.H, cid, 0);\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n\n    {\n        int cid = top[0];\n        auto occ = greedy_connect_mode(sel, cr, gd.w, gd.W, gd.H, cid, 1);\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n}\n\nvoid process_selection_light(\n    const GridData& gd,\n    const vector<char>& sel,\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    auto cr = get_components(sel, gd.w, gd.W, gd.H);\n    auto top = top_positive_components(cr, 2);\n    if (top.empty()) return;\n\n    for (int ti = 0; ti < (int)top.size(); ti++) {\n        int cid = top[ti];\n        vector<char> occ(gd.W * gd.H, 0);\n        for (int v : cr.comps[cid].cells) occ[v] = 1;\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n\n        if (ti == 0) {\n            auto box = bbox_occ_from_cells(cr.comps[cid].cells, gd.W, gd.H);\n            fill_holes(box, gd.W, gd.H);\n            try_add_candidate(cands, seenHash, gd, box, hasX, hasY);\n        }\n    }\n}\n\n// ----- final exact local optimization -----\n\nvoid extract_axis_levels(const Candidate& c, bool useX, vector<int>& levels, vector<int>& freq) {\n    levels.clear();\n    levels.reserve(c.poly.size());\n    for (const auto& p : c.poly) levels.push_back(useX ? p.x : p.y);\n    sort(levels.begin(), levels.end());\n    levels.erase(unique(levels.begin(), levels.end()), levels.end());\n\n    freq.assign(levels.size(), 0);\n    for (const auto& p : c.poly) {\n        int v = useX ? p.x : p.y;\n        int idx = (int)(lower_bound(levels.begin(), levels.end(), v) - levels.begin());\n        freq[idx]++;\n    }\n}\n\nvector<int> pick_level_indices(const vector<int>& levels, const vector<int>& freq, int K) {\n    int n = (int)levels.size();\n    vector<int> res;\n    if (n == 0) return res;\n\n    vector<char> used(n, 0);\n    auto take = [&](int i) {\n        if (0 <= i && i < n && !used[i]) {\n            used[i] = 1;\n            res.push_back(i);\n        }\n    };\n\n    take(0);\n    take(n - 1);\n\n    vector<pair<int,int>> ord;\n    ord.reserve(n);\n    for (int i = 0; i < n; i++) ord.push_back({-freq[i], i});\n    sort(ord.begin(), ord.end());\n\n    for (auto [nf, i] : ord) {\n        take(i);\n        if ((int)res.size() >= K) break;\n    }\n    return res;\n}\n\nvector<int> axis_candidate_values(const vector<int>& fishVals, int cur, int L, int R) {\n    vector<int> res;\n    auto add = [&](int v) {\n        if (v < L || v > R) return;\n        res.push_back(v);\n    };\n    auto add_fish = [&](int fv) {\n        if (fv < L || fv > R) return;\n        add(fv);\n        add(fv - 1);\n        add(fv + 1);\n    };\n\n    add(cur);\n    add(cur - 1);\n    add(cur + 1);\n    add(L);\n    add(R);\n    add((L + R) / 2);\n\n    auto proc_index = [&](int idx) {\n        if (0 <= idx && idx < (int)fishVals.size()) add_fish(fishVals[idx]);\n    };\n\n    int pos = (int)(lower_bound(fishVals.begin(), fishVals.end(), cur) - fishVals.begin());\n    for (int d = -4; d <= 4; d++) proc_index(pos + d);\n\n    int posL = (int)(lower_bound(fishVals.begin(), fishVals.end(), L) - fishVals.begin());\n    for (int d = -1; d <= 2; d++) proc_index(posL + d);\n\n    int posR = (int)(upper_bound(fishVals.begin(), fishVals.end(), R) - fishVals.begin()) - 1;\n    for (int d = -2; d <= 1; d++) proc_index(posR + d);\n\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    return res;\n}\n\nbool optimize_axis_once(\n    Candidate& cur,\n    int& curScore,\n    bool useX,\n    ExactScorer& scorer,\n    const vector<int>& fishVals,\n    const function<double()>& elapsed_ms,\n    double deadline_ms\n) {\n    if (elapsed_ms() > deadline_ms) return false;\n\n    vector<int> levels, freq;\n    extract_axis_levels(cur, useX, levels, freq);\n    if ((int)levels.size() <= 1) return false;\n\n    auto idxs = pick_level_indices(levels, freq, 6);\n\n    for (int idx : idxs) {\n        if (elapsed_ms() > deadline_ms) return false;\n\n        int oldv = levels[idx];\n        int L = (idx == 0 ? 0 : levels[idx - 1] + 1);\n        int R = (idx + 1 == (int)levels.size() ? COORD_MAX : levels[idx + 1] - 1);\n        if (L > R) continue;\n\n        auto candVals = axis_candidate_values(fishVals, oldv, L, R);\n\n        int bestSc = curScore;\n        Candidate bestCand;\n        bool found = false;\n\n        for (int nv : candVals) {\n            if (nv == oldv) continue;\n            vector<Pt> poly = cur.poly;\n            for (auto& p : poly) {\n                int& a = useX ? p.x : p.y;\n                if (a == oldv) a = nv;\n            }\n            if (!basic_valid_poly(poly)) continue;\n\n            Candidate cc = make_candidate(std::move(poly), cur.approx);\n            int sc = scorer.score(cc);\n\n            if (sc > bestSc || (sc == bestSc && cc.perim < cur.perim)) {\n                bestSc = sc;\n                bestCand = std::move(cc);\n                found = true;\n            }\n\n            if (elapsed_ms() > deadline_ms) break;\n        }\n\n        if (found) {\n            cur = std::move(bestCand);\n            curScore = bestSc;\n            return true;\n        }\n    }\n\n    return false;\n}\n\npair<Candidate,int> local_optimize_candidate(\n    Candidate cur,\n    int curScore,\n    ExactScorer& scorer,\n    const vector<int>& fishXs,\n    const vector<int>& fishYs,\n    const function<double()>& elapsed_ms,\n    double deadline_ms,\n    int maxRounds\n) {\n    if ((int)cur.poly.size() > 220) return {cur, curScore};\n\n    for (int round = 0; round < maxRounds; round++) {\n        if (elapsed_ms() > deadline_ms) break;\n        bool changed = false;\n        changed |= optimize_axis_once(cur, curScore, true, scorer, fishXs, elapsed_ms, deadline_ms);\n        if (elapsed_ms() > deadline_ms) break;\n        changed |= optimize_axis_once(cur, curScore, false, scorer, fishYs, elapsed_ms, deadline_ms);\n        if (!changed) break;\n    }\n    return {cur, curScore};\n}\n\nvoid update_elite(vector<pair<int,Candidate>>& elite, int sc, const Candidate& c) {\n    for (auto& e : elite) {\n        if (e.second.hash == c.hash) {\n            if (sc > e.first) e.first = sc;\n            return;\n        }\n    }\n    elite.push_back({sc, c});\n    sort(elite.begin(), elite.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        if (a.second.perim != b.second.perim) return a.second.perim < b.second.perim;\n        return a.second.poly.size() < b.second.poly.size();\n    });\n    if ((int)elite.size() > 3) elite.resize(3);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, std::milli>(chrono::steady_clock::now() - t0).count();\n    };\n\n    int N;\n    cin >> N;\n\n    vector<Pt> macks(N), sards(N);\n    unordered_set<long long> allPts;\n    allPts.reserve((size_t)2 * N * 2);\n\n    vector<char> hasX(COORD_MAX + 1, 0), hasY(COORD_MAX + 1, 0);\n    vector<int> fishXs, fishYs;\n    fishXs.reserve(2 * N);\n    fishYs.reserve(2 * N);\n\n    for (int i = 0; i < N; i++) {\n        cin >> macks[i].x >> macks[i].y;\n        allPts.insert(1LL * macks[i].x * (COORD_MAX + 1) + macks[i].y);\n        hasX[macks[i].x] = 1;\n        hasY[macks[i].y] = 1;\n        fishXs.push_back(macks[i].x);\n        fishYs.push_back(macks[i].y);\n    }\n    for (int i = 0; i < N; i++) {\n        cin >> sards[i].x >> sards[i].y;\n        allPts.insert(1LL * sards[i].x * (COORD_MAX + 1) + sards[i].y);\n        hasX[sards[i].x] = 1;\n        hasY[sards[i].y] = 1;\n        fishXs.push_back(sards[i].x);\n        fishYs.push_back(sards[i].y);\n    }\n\n    sort(fishXs.begin(), fishXs.end());\n    fishXs.erase(unique(fishXs.begin(), fishXs.end()), fishXs.end());\n    sort(fishYs.begin(), fishYs.end());\n    fishYs.erase(unique(fishYs.begin(), fishYs.end()), fishYs.end());\n\n    FishEnv env;\n    env.pts.reserve(2 * N);\n    env.sgn.reserve(2 * N);\n    env.byX.assign(COORD_MAX + 1, {});\n    env.byY.assign(COORD_MAX + 1, {});\n\n    for (int i = 0; i < N; i++) {\n        int idx = (int)env.pts.size();\n        env.pts.push_back(macks[i]);\n        env.sgn.push_back(+1);\n        env.byX[macks[i].x].push_back(idx);\n        env.byY[macks[i].y].push_back(idx);\n    }\n    for (int i = 0; i < N; i++) {\n        int idx = (int)env.pts.size();\n        env.pts.push_back(sards[i]);\n        env.sgn.push_back(-1);\n        env.byX[sards[i].x].push_back(idx);\n        env.byY[sards[i].y].push_back(idx);\n    }\n\n    env.ordY.resize(env.pts.size());\n    iota(env.ordY.begin(), env.ordY.end(), 0);\n    sort(env.ordY.begin(), env.ordY.end(), [&](int a, int b) {\n        if (env.pts[a].y != env.pts[b].y) return env.pts[a].y < env.pts[b].y;\n        return env.pts[a].x < env.pts[b].x;\n    });\n\n    vector<Candidate> cands;\n    cands.reserve(2600);\n    unordered_set<uint64_t> seenHash;\n    seenHash.reserve(12000);\n\n    // Light ultra-fine pass\n    {\n        int G = 800;\n        vector<pair<int,int>> shifts = {{0, 0}, {G / 2, G / 2}};\n        for (auto [sx, sy] : shifts) {\n            if (elapsed_ms() > 350.0) break;\n            GridData gd = build_grid(macks, sards, G, sx, sy);\n\n            {\n                auto occ = best_rectangle_region(gd);\n                try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n            }\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                for (int i = 0; i < gd.W * gd.H; i++) if (gd.w[i] > 0) sel[i] = 1;\n                process_selection_light(gd, sel, cands, seenHash, hasX, hasY);\n            }\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 2) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection_light(gd, sel, cands, seenHash, hasX, hasY);\n            }\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 3) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection_light(gd, sel, cands, seenHash, hasX, hasY);\n            }\n        }\n    }\n\n    vector<int> Gs = {1000, 1400, 1800, 2300, 3000};\n\n    bool stopGen = false;\n    for (int G : Gs) {\n        vector<pair<int,int>> shifts = {\n            {0, 0},\n            {0, G / 2},\n            {G / 2, 0},\n            {G / 2, G / 2}\n        };\n\n        vector<int> lambdas;\n        if (G == 1000) lambdas = {1};\n        else if (G <= 1800) lambdas = {1, 2};\n        else lambdas = {1, 2, 3};\n\n        for (auto [sx, sy] : shifts) {\n            if (elapsed_ms() > 1700.0) { stopGen = true; break; }\n\n            GridData gd = build_grid(macks, sards, G, sx, sy);\n\n            {\n                auto occ = best_rectangle_region(gd);\n                try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n            }\n\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                for (int i = 0; i < gd.W * gd.H; i++) if (gd.w[i] > 0) sel[i] = 1;\n                process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 2) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            if (G <= 1400) {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 3) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            if (G >= 2300) {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool anyPos = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 0) sel[i] = 1;\n                    if (gd.w[i] > 0) anyPos = true;\n                }\n                if (anyPos) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            for (int lambda : lambdas) {\n                if (elapsed_ms() > 1770.0) { stopGen = true; break; }\n                auto sel = graph_cut_select(gd, lambda);\n                process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n            if (stopGen) break;\n        }\n        if (stopGen) break;\n    }\n\n    Candidate best = make_candidate(find_empty_square(allPts), 0);\n    ExactScorer scorer(env);\n    int bestScore = scorer.score(best);\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.perim != b.perim) return a.perim < b.perim;\n        return a.poly.size() < b.poly.size();\n    });\n\n    vector<pair<int,Candidate>> elite;\n    update_elite(elite, bestScore, best);\n\n    for (const auto& c : cands) {\n        if (elapsed_ms() > 1980.0) break;\n        int sc = scorer.score(c);\n        if (sc > bestScore) {\n            bestScore = sc;\n            best = c;\n        }\n        update_elite(elite, sc, c);\n    }\n\n    // Small exact local coordinate optimization on elite candidates\n    sort(elite.begin(), elite.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        if (a.second.perim != b.second.perim) return a.second.perim < b.second.perim;\n        return a.second.poly.size() < b.second.poly.size();\n    });\n\n    for (int i = 0; i < (int)elite.size(); i++) {\n        if (elapsed_ms() > 1993.0) break;\n        int rounds = (i == 0 ? 2 : 1);\n        auto [cand2, sc2] = local_optimize_candidate(\n            elite[i].second, elite[i].first, scorer,\n            fishXs, fishYs, elapsed_ms, 1993.0, rounds\n        );\n        if (sc2 > bestScore) {\n            bestScore = sc2;\n            best = std::move(cand2);\n        }\n    }\n\n    cout << best.poly.size() << '\\n';\n    for (auto& p : best.poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Dim {\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 baseScore = 1e100;\n    double robustScore = 1e100;\n    uint64_t hash = 0;\n};\n\nstruct ShelfSol {\n    char dir = 'L'; // 'L': row shelves, 'U': column shelves\n    vector<unsigned char> used, rot, brk; // if used[i], brk[i]=1 means starts new group\n    double score = 1e100;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstatic uint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    h ^= splitmix64((uint64_t)ops.size());\n    for (const auto& op : ops) {\n        uint64_t v = 0;\n        v ^= (uint64_t)(op.p + 1) * 1000003ULL;\n        v ^= (uint64_t)(op.r + 7) * 10007ULL;\n        v ^= (uint64_t)(unsigned char)(op.d) * 911382323ULL;\n        v ^= (uint64_t)(op.b + 2) * 972663749ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\nstatic bool overlap1D(double l1, double r1, double l2, double r2) {\n    const double EPS = 1e-9;\n    return max(l1, l2) + EPS < min(r1, r2);\n}\n\nstatic double exact_score(const vector<Dim>& dims, const vector<Op>& ops) {\n    int N = (int)dims.size();\n    vector<double> x1(N, 0), y1(N, 0), x2(N, 0), y2(N, 0);\n    vector<char> placed(N, 0), used(N, 0);\n\n    double W = 0, H = 0;\n\n    for (const auto& op : ops) {\n        int p = op.p;\n        double w = op.r ? dims[p].h : dims[p].w;\n        double h = op.r ? dims[p].w : dims[p].h;\n\n        double x = 0, y = 0;\n\n        if (op.d == 'U') {\n            x = (op.b == -1 ? 0.0 : x2[op.b]);\n            y = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(x, x + w, x1[j], x2[j])) {\n                    y = max(y, y2[j]);\n                }\n            }\n        } else {\n            y = (op.b == -1 ? 0.0 : y2[op.b]);\n            x = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(y, y + h, y1[j], y2[j])) {\n                    x = max(x, x2[j]);\n                }\n            }\n        }\n\n        x1[p] = x; y1[p] = y;\n        x2[p] = x + w; y2[p] = y + h;\n        placed[p] = used[p] = 1;\n\n        W = max(W, x2[p]);\n        H = max(H, y2[p]);\n    }\n\n    double penalty = 0.0;\n    for (int i = 0; i < N; i++) {\n        if (!used[i]) penalty += dims[i].w + dims[i].h;\n    }\n    return W + H + penalty;\n}\n\nstatic pair<long long, long long> query_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n\n    long long W, H;\n    if (!(cin >> W >> H)) exit(0);\n    if (W < 0 || H < 0) exit(0);\n    return {W, H};\n}\n\nstatic vector<Op> make_line_ops(const vector<int>& ids, char dir, int rot = 0) {\n    vector<Op> ops;\n    ops.reserve(ids.size());\n    for (int x : ids) ops.push_back({x, rot, dir, -1});\n    return ops;\n}\n\nstatic vector<Op> make_all_line_ops(int N, char dir, int rot = 0) {\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    return make_line_ops(ids, dir, rot);\n}\n\nstatic vector<int> top_k_indices(const vector<double>& vals, int K) {\n    int N = (int)vals.size();\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    if (K <= 0) return {};\n    if (K >= N) return ids;\n    nth_element(ids.begin(), ids.begin() + K, ids.end(), [&](int a, int b) {\n        return vals[a] > vals[b];\n    });\n    ids.resize(K);\n    sort(ids.begin(), ids.end());\n    return ids;\n}\n\nstatic vector<double> correct_groupwise(\n    const vector<double>& y,\n    double totalM, double tauTotal,\n    const vector<int>* subset,\n    double subsetM, double tauSubset\n) {\n    int N = (int)y.size();\n    vector<double> x(N);\n    double Sy = 0.0;\n    for (double v : y) Sy += v;\n\n    if (subset == nullptr || subset->empty() || (int)subset->size() == N || subsetM < 0) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    vector<char> inS(N, 0);\n    double SS = 0.0;\n    for (int idx : *subset) {\n        inS[idx] = 1;\n        SS += y[idx];\n    }\n    double nS = (double)subset->size();\n\n    double d0 = Sy - totalM;\n    double d1 = SS - subsetM;\n\n    double a11 = N + tauTotal;\n    double a12 = nS;\n    double a21 = nS;\n    double a22 = nS + tauSubset;\n    double det = a11 * a22 - a12 * a21;\n\n    if (fabs(det) < 1e-12) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    double A = (d0 * a22 - d1 * a12) / det;\n    double B = (a11 * d1 - a21 * d0) / det;\n\n    for (int i = 0; i < N; i++) {\n        double v = y[i] - A - (inS[i] ? B : 0.0);\n        x[i] = max(1.0, v);\n    }\n    return x;\n}\n\nstatic vector<double> sample_cond_1d(\n    const vector<double>& obs,\n    double totalM, double tauTotal,\n    const vector<int>* subset,\n    double subsetM, double tauSubset,\n    double sigma,\n    double alpha,\n    mt19937_64& rng\n) {\n    static normal_distribution<double> nd(0.0, 1.0);\n    vector<double> y = obs;\n    for (double& v : y) v += nd(rng) * alpha * sigma;\n    return correct_groupwise(y, totalM, tauTotal, subset, subsetM, tauSubset);\n}\n\nstatic vector<Dim> sample_world_conditioned(\n    const vector<double>& obsW,\n    const vector<double>& obsH,\n    double totalW, double tauW,\n    const vector<int>* subsetW, double subsetWM, double tauSW,\n    double totalH, double tauH,\n    const vector<int>* subsetH, double subsetHM, double tauSH,\n    double sigma,\n    double alpha,\n    mt19937_64& rng\n) {\n    int N = (int)obsW.size();\n    vector<double> sw = sample_cond_1d(obsW, totalW, tauW, subsetW, subsetWM, tauSW, sigma, alpha, rng);\n    vector<double> sh = sample_cond_1d(obsH, totalH, tauH, subsetH, subsetHM, tauSH, sigma, alpha, rng);\n    vector<Dim> out(N);\n    for (int i = 0; i < N; i++) out[i] = {sw[i], sh[i]};\n    return out;\n}\n\nstatic inline void get_ab(const Dim& d, char dir, int rot, double& a, double& b) {\n    if (dir == 'L') {\n        a = rot ? d.h : d.w;\n        b = rot ? d.w : d.h;\n    } else {\n        a = rot ? d.w : d.h;\n        b = rot ? d.h : d.w;\n    }\n}\n\nstatic inline double metric_b(const Dim& d, char dir, int rot) {\n    if (dir == 'L') return rot ? d.w : d.h;\n    return rot ? d.h : d.w;\n}\n\nstatic void normalize_shelf(ShelfSol& s) {\n    int N = (int)s.used.size();\n    for (int i = 0; i < N; i++) if (!s.used[i]) s.brk[i] = 0;\n    int first = -1;\n    for (int i = 0; i < N; i++) if (s.used[i]) {\n        first = i;\n        break;\n    }\n    if (first != -1) s.brk[first] = 1;\n}\n\nstatic double shelf_score_fast(const vector<Dim>& dims, const ShelfSol& s) {\n    int N = (int)dims.size();\n    double pen = 0.0;\n    double maxA = 0.0, sumB = 0.0;\n    double curA = 0.0, curB = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) {\n            pen += dims[i].w + dims[i].h;\n            continue;\n        }\n        double a, b;\n        get_ab(dims[i], s.dir, s.rot[i], a, b);\n\n        if (!active || s.brk[i]) {\n            if (active) {\n                maxA = max(maxA, curA);\n                sumB += curB;\n            }\n            curA = a;\n            curB = b;\n            active = true;\n        } else {\n            curA += a;\n            curB = max(curB, b);\n        }\n    }\n\n    if (active) {\n        maxA = max(maxA, curA);\n        sumB += curB;\n    }\n    return pen + maxA + sumB;\n}\n\nstatic double shelf_score_multi(const vector<vector<Dim>>& worlds, const ShelfSol& s) {\n    double sum = 0.0, mx = -1e100;\n    for (const auto& w : worlds) {\n        double sc = shelf_score_fast(w, s);\n        sum += sc;\n        mx = max(mx, sc);\n    }\n    double mean = sum / worlds.size();\n    return mean + 0.05 * (mx - mean);\n}\n\nstatic Candidate shelf_to_candidate(const vector<Dim>& base, const ShelfSol& s) {\n    int N = (int)base.size();\n\n    vector<vector<pair<int,int>>> groups;\n    bool active = false;\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) continue;\n        if (!active || s.brk[i]) {\n            groups.emplace_back();\n            active = true;\n        }\n        groups.back().push_back({i, (int)s.rot[i]});\n    }\n\n    vector<int> reps;\n    reps.reserve(groups.size());\n\n    for (auto& g : groups) {\n        int bestIdx = g[0].first;\n        double bestM = metric_b(base[g[0].first], s.dir, g[0].second);\n        for (auto [idx, r] : g) {\n            double m = metric_b(base[idx], s.dir, r);\n            if (m > bestM) {\n                bestM = m;\n                bestIdx = idx;\n            }\n        }\n        reps.push_back(bestIdx);\n    }\n\n    vector<Op> ops;\n    for (int gi = 0; gi < (int)groups.size(); gi++) {\n        int bref = (gi == 0 ? -1 : reps[gi - 1]);\n        for (auto [idx, r] : groups[gi]) {\n            ops.push_back({idx, r, s.dir, bref});\n        }\n    }\n\n    Candidate c;\n    c.ops = move(ops);\n    c.baseScore = exact_score(base, c.ops);\n    c.hash = hash_ops(c.ops);\n    return c;\n}\n\nstatic ShelfSol candidate_to_shelf(const Candidate& c, int N) {\n    ShelfSol s;\n    s.dir = c.ops.empty() ? 'L' : c.ops[0].d;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool first = true;\n    int curb = INT_MIN;\n    for (const auto& op : c.ops) {\n        s.used[op.p] = 1;\n        s.rot[op.p] = (unsigned char)op.r;\n        if (first || op.b != curb) {\n            s.brk[op.p] = 1;\n            curb = op.b;\n            first = false;\n        }\n    }\n    normalize_shelf(s);\n    return s;\n}\n\nstatic double total_area(const vector<Dim>& dims) {\n    long double s = 0;\n    for (auto& d : dims) s += (long double)d.w * d.h;\n    return (double)s;\n}\n\nstruct Node {\n    int parent = -1;\n    unsigned char act = 0; // 0=skip, 1=continue/start, 2=new group\n    unsigned char rot = 0;\n    double maxDoneA = 0;\n    double sumDoneB = 0;\n    double curA = 0;\n    double curB = 0;\n    double pen = 0;\n    double eval = 0;\n};\n\nstatic inline double node_exact_score(const Node& s) {\n    return s.pen + max(s.maxDoneA, s.curA) + s.sumDoneB + s.curB;\n}\n\nstatic Candidate beam_shelf(\n    const vector<Dim>& sample,\n    const vector<Dim>& base,\n    char dir,\n    double targetA,\n    int beamWidth,\n    double omitMul\n) {\n    int N = (int)sample.size();\n    vector<double> a0(N), b0(N), a1(N), b1(N), remArea(N + 1);\n\n    for (int i = 0; i < N; i++) {\n        double a, b;\n        get_ab(sample[i], dir, 0, a, b);\n        a0[i] = a; b0[i] = b;\n        get_ab(sample[i], dir, 1, a, b);\n        a1[i] = a; b1[i] = b;\n    }\n\n    remArea[N] = 0.0;\n    for (int i = N - 1; i >= 0; i--) {\n        remArea[i] = remArea[i + 1] + sample[i].w * sample[i].h;\n    }\n\n    auto calc_eval = [&](double maxDoneA, double sumDoneB, double curA, double curB, double pen, int nexti) -> double {\n        double nowA = max(maxDoneA, curA);\n        double assumedA = max(nowA, targetA);\n        if (assumedA < 1.0) assumedA = 1.0;\n        return pen + assumedA + sumDoneB + curB + remArea[nexti] / assumedA;\n    };\n\n    vector<Node> nodes;\n    nodes.reserve(1 + (size_t)N * beamWidth * 5 + 16);\n    nodes.push_back(Node());\n    nodes[0].eval = calc_eval(0, 0, 0, 0, 0, 0);\n\n    vector<int> beam, nxt;\n    beam.push_back(0);\n\n    auto cmp = [&](int x, int y) {\n        if (nodes[x].eval != nodes[y].eval) return nodes[x].eval < nodes[y].eval;\n        return node_exact_score(nodes[x]) < node_exact_score(nodes[y]);\n    };\n\n    for (int i = 0; i < N; i++) {\n        nxt.clear();\n        nxt.reserve((size_t)beam.size() * 5 + 8);\n\n        for (int id : beam) {\n            const Node& s = nodes[id];\n\n            {\n                Node t = s;\n                t.parent = id;\n                t.act = 0;\n                t.rot = 0;\n                t.pen = s.pen + omitMul * (sample[i].w + sample[i].h);\n                t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                nodes.push_back(t);\n                nxt.push_back((int)nodes.size() - 1);\n            }\n\n            for (int r = 0; r < 2; r++) {\n                double a = (r ? a1[i] : a0[i]);\n                double b = (r ? b1[i] : b0[i]);\n\n                if (s.curA == 0.0 && s.curB == 0.0 && s.maxDoneA == 0.0 && s.sumDoneB == 0.0) {\n                    Node t;\n                    t.parent = id;\n                    t.act = 1;\n                    t.rot = (unsigned char)r;\n                    t.curA = a;\n                    t.curB = b;\n                    t.pen = s.pen;\n                    t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                    nodes.push_back(t);\n                    nxt.push_back((int)nodes.size() - 1);\n                } else {\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 1;\n                        t.rot = (unsigned char)r;\n                        t.curA = s.curA + a;\n                        t.curB = max(s.curB, b);\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 2;\n                        t.rot = (unsigned char)r;\n                        t.maxDoneA = max(s.maxDoneA, s.curA);\n                        t.sumDoneB = s.sumDoneB + s.curB;\n                        t.curA = a;\n                        t.curB = b;\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                }\n            }\n        }\n\n        if ((int)nxt.size() > beamWidth) {\n            nth_element(nxt.begin(), nxt.begin() + beamWidth, nxt.end(), cmp);\n            nxt.resize(beamWidth);\n        }\n        sort(nxt.begin(), nxt.end(), cmp);\n        beam.swap(nxt);\n    }\n\n    int bestId = beam[0];\n    double bestExact = node_exact_score(nodes[bestId]);\n    for (int id : beam) {\n        double sc = node_exact_score(nodes[id]);\n        if (sc < bestExact) {\n            bestExact = sc;\n            bestId = id;\n        }\n    }\n\n    vector<int> act(N, 0), rot(N, 0);\n    int cur = bestId;\n    for (int i = N - 1; i >= 0; i--) {\n        act[i] = nodes[cur].act;\n        rot[i] = nodes[cur].rot;\n        cur = nodes[cur].parent;\n    }\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool started = false;\n    for (int i = 0; i < N; i++) {\n        if (act[i] == 0) continue;\n        s.used[i] = 1;\n        s.rot[i] = (unsigned char)rot[i];\n        if (!started || act[i] == 2) {\n            s.brk[i] = 1;\n            started = true;\n        }\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    return shelf_to_candidate(base, s);\n}\n\nstatic ShelfSol random_seed_shelf(const vector<Dim>& base, char dir, double targetA, mt19937_64& rng) {\n    int N = (int)base.size();\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    double curA = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (ur(rng) < 0.03) continue;\n\n        double a0, b0, a1, b1;\n        get_ab(base[i], dir, 0, a0, b0);\n        get_ab(base[i], dir, 1, a1, b1);\n\n        double fit0 = fabs((active ? curA : 0.0) + a0 - targetA) + 0.30 * b0;\n        double fit1 = fabs((active ? curA : 0.0) + a1 - targetA) + 0.30 * b1;\n        int r = (fit1 < fit0 ? 1 : 0);\n\n        double a = (r ? a1 : a0);\n        bool newg = !active || curA + a > targetA * (0.85 + 0.40 * ur(rng));\n\n        s.used[i] = 1;\n        s.rot[i] = (unsigned char)r;\n        if (newg) {\n            s.brk[i] = 1;\n            curA = a;\n            active = true;\n        } else {\n            curA += a;\n        }\n    }\n\n    if (!active) {\n        int i = (int)(rng() % N);\n        s.used[i] = 1;\n        s.rot[i] = (unsigned char)(rng() & 1);\n        s.brk[i] = 1;\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    return s;\n}\n\nstatic void mutate_once(ShelfSol& s, mt19937_64& rng) {\n    int N = (int)s.used.size();\n    int typ = (int)(rng() % 100);\n    int i = (int)(rng() % N);\n\n    if (typ < 40) {\n        if (s.used[i]) {\n            s.rot[i] ^= 1;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else if (typ < 75) {\n        if (s.used[i]) {\n            s.used[i] = 0;\n            s.brk[i] = 0;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else {\n        if (s.used[i]) s.brk[i] ^= 1;\n    }\n}\n\nstatic ShelfSol greedy_polish(const vector<vector<Dim>>& worlds, ShelfSol s) {\n    int N = (int)s.used.size();\n    normalize_shelf(s);\n    double cur = shelf_score_multi(worlds, s);\n\n    for (int round = 0; round < 3; round++) {\n        bool improved = false;\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.rot[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_multi(worlds, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.brk[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_multi(worlds, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (s.used[i]) {\n                ShelfSol t = s;\n                t.used[i] = 0;\n                t.brk[i] = 0;\n                normalize_shelf(t);\n                double sc = shelf_score_multi(worlds, t);\n                if (sc + 1e-9 < cur) {\n                    s = move(t);\n                    cur = sc;\n                    improved = true;\n                }\n            } else {\n                double bestSc = cur;\n                ShelfSol bestT = s;\n                for (int r = 0; r < 2; r++) {\n                    for (int b = 0; b < 2; b++) {\n                        ShelfSol t = s;\n                        t.used[i] = 1;\n                        t.rot[i] = (unsigned char)r;\n                        t.brk[i] = (unsigned char)b;\n                        normalize_shelf(t);\n                        double sc = shelf_score_multi(worlds, t);\n                        if (sc + 1e-9 < bestSc) {\n                            bestSc = sc;\n                            bestT = move(t);\n                        }\n                    }\n                }\n                if (bestSc + 1e-9 < cur) {\n                    s = move(bestT);\n                    cur = bestSc;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    s.score = cur;\n    return s;\n}\n\nstatic ShelfSol local_search(\n    const vector<vector<Dim>>& worlds,\n    ShelfSol seed,\n    mt19937_64& rng,\n    int iterations,\n    chrono::steady_clock::time_point deadline\n) {\n    normalize_shelf(seed);\n    seed.score = shelf_score_multi(worlds, seed);\n\n    ShelfSol cur = seed, best = seed;\n    double curSc = seed.score, bestSc = seed.score;\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 255) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n\n        ShelfSol nxt = cur;\n        int moves = ((rng() % 5) == 0 ? 2 : 1);\n        for (int k = 0; k < moves; k++) mutate_once(nxt, rng);\n        normalize_shelf(nxt);\n        double sc = shelf_score_multi(worlds, nxt);\n\n        double prog = (double)it / max(1, iterations - 1);\n        double temp = 25000.0 * pow(0.002, prog) + 1.0;\n\n        if (sc < curSc || ur(rng) < exp((curSc - sc) / temp)) {\n            cur = move(nxt);\n            curSc = sc;\n            if (curSc < bestSc) {\n                best = cur;\n                bestSc = curSc;\n            }\n        }\n    }\n\n    best.score = bestSc;\n    best = greedy_polish(worlds, best);\n    return best;\n}\n\nstatic double robust_eval_candidate(const Candidate& cand, const vector<vector<Dim>>& worlds) {\n    double sum = 0.0, mx = -1e100;\n    for (const auto& w : worlds) {\n        double sc = exact_score(w, cand.ops);\n        sum += sc;\n        mx = max(mx, sc);\n    }\n    double mean = sum / worlds.size();\n    return mean + 0.08 * (mx - mean);\n}\n\nstatic vector<Candidate> generate_candidates(\n    const vector<Dim>& base,\n    const vector<vector<Dim>>& searchWorlds,\n    const vector<vector<Dim>>& rankWorlds,\n    int remainingTurns,\n    mt19937_64& rng,\n    chrono::steady_clock::time_point deadline\n) {\n    int N = (int)base.size();\n    double rootArea = sqrt(max(1.0, total_area(base)));\n\n    int beamDet = (N <= 60 ? 520 : 380);\n    int beamRnd = (N <= 60 ? 220 : 160);\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    auto add_cand = [&](Candidate cand) {\n        cand.hash = hash_ops(cand.ops);\n        if (seen.insert(cand.hash).second) {\n            pool.push_back(move(cand));\n        }\n    };\n\n    // Baseline straight-line candidates\n    for (int rot = 0; rot < 2; rot++) {\n        for (char dir : {'L', 'U'}) {\n            Candidate c;\n            c.ops = make_all_line_ops(N, dir, rot);\n            c.baseScore = exact_score(base, c.ops);\n            c.hash = hash_ops(c.ops);\n            add_cand(move(c));\n        }\n    }\n\n    vector<double> scales = {0.50, 0.63, 0.78, 0.92, 1.05, 1.20, 1.38, 1.60, 1.88};\n    vector<double> omits = {1.00, 1.12, 1.25, 1.40};\n\n    // Deterministic beams on base and a couple conditioned worlds.\n    int useWorlds = min((int)searchWorlds.size(), 3);\n    for (int wi = 0; wi < useWorlds; wi++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        const auto& w = searchWorlds[wi];\n        for (double sc : scales) {\n            add_cand(beam_shelf(w, base, 'L', rootArea * sc, beamDet, 1.15));\n            add_cand(beam_shelf(w, base, 'U', rootArea * sc, beamDet, 1.15));\n        }\n    }\n    for (double om : omits) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        add_cand(beam_shelf(base, base, 'L', rootArea, beamDet, om));\n        add_cand(beam_shelf(base, base, 'U', rootArea, beamDet, om));\n    }\n\n    // Randomized beams on conditioned worlds.\n    uniform_real_distribution<double> ul(log(0.45), log(2.20));\n    int randomBeamAttempts = min(120, remainingTurns + 50);\n    for (int it = 0; it < randomBeamAttempts; it++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        const auto& sample = searchWorlds[(int)(rng() % searchWorlds.size())];\n        double tgt = sqrt(max(1.0, total_area(sample))) * exp(ul(rng));\n        char dir = ((rng() & 1) ? 'L' : 'U');\n        double om = omits[(size_t)(rng() % omits.size())];\n        add_cand(beam_shelf(sample, base, dir, tgt, beamRnd, om));\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.baseScore < b.baseScore;\n    });\n\n    // Local search on top beam seeds.\n    vector<Candidate> enhanced = pool;\n    int topSeeds = min((int)pool.size(), 14);\n    for (int i = 0; i < topSeeds; i++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        ShelfSol s = candidate_to_shelf(pool[i], N);\n        int iters = (i < 8 ? 4500 : 2200);\n        ShelfSol best = local_search(searchWorlds, s, rng, iters, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    // Random seeds + local search.\n    for (int t = 0; t < 8; t++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        char dir = (t & 1) ? 'L' : 'U';\n        double sc = exp(ul(rng));\n        ShelfSol s = random_seed_shelf(base, dir, rootArea * sc, rng);\n        ShelfSol best = local_search(searchWorlds, s, rng, 1800, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    for (auto& c : enhanced) {\n        c.robustScore = robust_eval_candidate(c, rankWorlds);\n    }\n\n    sort(enhanced.begin(), enhanced.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.robustScore != b.robustScore) return a.robustScore < b.robustScore;\n        return a.baseScore < b.baseScore;\n    });\n\n    if ((int)enhanced.size() > 260) enhanced.resize(260);\n    return enhanced;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    int N, T, sigma_i;\n    cin >> N >> T >> sigma_i;\n    double sigma = sigma_i;\n\n    vector<Dim> obs(N);\n    for (int i = 0; i < N; i++) {\n        cin >> obs[i].w >> obs[i].h;\n    }\n\n    mt19937_64 rng(0x3141592653589793ULL);\n\n    vector<double> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) {\n        obsW[i] = obs[i].w;\n        obsH[i] = obs[i].h;\n    }\n\n    int usedTurns = 0;\n\n    // Calibration plan:\n    // always: total width, total height\n    // if T large enough: focused subset width/height\n    // if T larger: repeated totals via rotated full-line queries\n    bool useSubset = (T >= 20);\n    bool useRepeatTotals = (T >= 32);\n\n    int K = min(max(6, N / 4), 20);\n    vector<int> subsetW = top_k_indices(obsW, K);\n    vector<int> subsetH = top_k_indices(obsH, K);\n\n    vector<double> totalWidthMeasures, totalHeightMeasures;\n    double subsetWidthMeasure = -1.0, subsetHeightMeasure = -1.0;\n\n    // 1) total width by all-in-row, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 0));\n        (void)Hm;\n        totalWidthMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 2) total height by all-in-column, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 0));\n        (void)Wm;\n        totalHeightMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    // 3) focused width subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetW, 'L', 0));\n        (void)Hm;\n        subsetWidthMeasure = (double)Wm;\n        usedTurns++;\n    }\n\n    // 4) focused height subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetH, 'U', 0));\n        (void)Wm;\n        subsetHeightMeasure = (double)Hm;\n        usedTurns++;\n    }\n\n    // 5) repeat total height via all-in-row, rotated\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 1));\n        (void)Hm;\n        totalHeightMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 6) repeat total width via all-in-column, rotated\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 1));\n        (void)Wm;\n        totalWidthMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    int remainingTurns = T - usedTurns;\n    if (remainingTurns <= 0) return 0;\n\n    auto avg = [](const vector<double>& v) {\n        double s = 0.0;\n        for (double x : v) s += x;\n        return s / v.size();\n    };\n\n    double totalW = avg(totalWidthMeasures);\n    double totalH = avg(totalHeightMeasures);\n    double tauW = 1.0 / (double)totalWidthMeasures.size();\n    double tauH = 1.0 / (double)totalHeightMeasures.size();\n\n    vector<double> corrW = correct_groupwise(\n        obsW, totalW, tauW,\n        (subsetWidthMeasure >= 0 ? &subsetW : nullptr),\n        subsetWidthMeasure, 1.0\n    );\n    vector<double> corrH = correct_groupwise(\n        obsH, totalH, tauH,\n        (subsetHeightMeasure >= 0 ? &subsetH : nullptr),\n        subsetHeightMeasure, 1.0\n    );\n\n    vector<Dim> base(N);\n    for (int i = 0; i < N; i++) {\n        base[i].w = corrW[i];\n        base[i].h = corrH[i];\n    }\n\n    // Search worlds: moderate number for local search.\n    vector<vector<Dim>> searchWorlds;\n    searchWorlds.push_back(base);\n    for (double a : {0.70, 1.10, 1.50}) {\n        searchWorlds.push_back(sample_world_conditioned(\n            obsW, obsH,\n            totalW, tauW, (subsetWidthMeasure >= 0 ? &subsetW : nullptr), subsetWidthMeasure, 1.0,\n            totalH, tauH, (subsetHeightMeasure >= 0 ? &subsetH : nullptr), subsetHeightMeasure, 1.0,\n            sigma, a, rng\n        ));\n    }\n\n    // Ranking worlds: a bit wider.\n    vector<vector<Dim>> rankWorlds = searchWorlds;\n    rankWorlds.push_back(sample_world_conditioned(\n        obsW, obsH,\n        totalW, tauW, (subsetWidthMeasure >= 0 ? &subsetW : nullptr), subsetWidthMeasure, 1.0,\n        totalH, tauH, (subsetHeightMeasure >= 0 ? &subsetH : nullptr), subsetHeightMeasure, 1.0,\n        sigma, 0.45, rng\n    ));\n    rankWorlds.push_back(sample_world_conditioned(\n        obsW, obsH,\n        totalW, tauW, (subsetWidthMeasure >= 0 ? &subsetW : nullptr), subsetWidthMeasure, 1.0,\n        totalH, tauH, (subsetHeightMeasure >= 0 ? &subsetH : nullptr), subsetHeightMeasure, 1.0,\n        sigma, 1.90, rng\n    ));\n\n    auto deadline = startTime + chrono::milliseconds(2250);\n    auto pool = generate_candidates(base, searchWorlds, rankWorlds, remainingTurns, rng, deadline);\n    if (pool.empty()) {\n        pool.push_back(beam_shelf(base, base, 'L', sqrt(max(1.0, total_area(base))), 200, 1.2));\n    }\n\n    // Fixed schedule: mostly best candidates, but with some diversification.\n    int P = (int)pool.size();\n    vector<int> order;\n    vector<char> used(P, 0);\n\n    int cap = min(P, max(remainingTurns, min(P, remainingTurns * 3)));\n    int topTake = min(cap, max(5, remainingTurns * 2 / 3));\n\n    for (int i = 0; i < topTake; i++) {\n        if (!used[i]) {\n            used[i] = 1;\n            order.push_back(i);\n        }\n    }\n\n    int rem = remainingTurns - (int)order.size();\n    if (rem > 0 && cap > topTake) {\n        for (int s = 0; s < rem; s++) {\n            int idx = topTake + (int)((long long)(2 * s + 1) * (cap - topTake) / (2LL * rem));\n            idx = min(idx, cap - 1);\n            if (!used[idx]) {\n                used[idx] = 1;\n                order.push_back(idx);\n            }\n        }\n    }\n\n    for (int i = topTake; i < P && (int)order.size() < remainingTurns; i++) {\n        if (!used[i]) {\n            used[i] = 1;\n            order.push_back(i);\n        }\n    }\n\n    // Safe fallback: repeat best candidates if the pool is smaller than remaining turns.\n    while ((int)order.size() < remainingTurns) {\n        order.push_back(order.empty() ? 0 : order[(int)order.size() % max(1, min(P, 8))]);\n    }\n\n    for (int t = 0; t < remainingTurns; t++) {\n        auto resp = query_ops(pool[order[t]].ops);\n        (void)resp;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MAXN = 1000;\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int,int>> edges;\n    vector<vector<int>> g;\n    vector<int> deg;\n    vector<int> X, Y;\n    vector<bitset<MAXN>> adjMat;\n\n    mt19937_64 rng{chrono::steady_clock::now().time_since_epoch().count()};\n    chrono::steady_clock::time_point start_time, deadline;\n\n    struct State {\n        vector<vector<int>> children;\n        vector<vector<int>> comps;\n        vector<int> roots;\n        vector<int> depth, tin, tout, compId;\n        vector<int> subtreeBeauty;\n        vector<int> maxAbsDepth;\n        long long score = 0;\n    };\n\n    struct Move {\n        long long gain = 0;\n        int par = -1;\n        int child = -1;\n        int parentSub = 0;\n        int parDepth = 0;\n        int parentDeg = 0;\n        int parentA = 0;\n        int childSub = 0;\n    };\n\n    struct DMove {\n        // type: 0 = raise v, 1 = swap (v at d, u at d+1) -> (d+1, d)\n        int type = -1;\n        int v = -1, u = -1;\n        int gain = 0;\n        int newDepth = -1; // depth of moved-up vertex after move\n        int upA = 0, downA = 0;\n    };\n\n    bool time_up() const {\n        return chrono::steady_clock::now() >= deadline;\n    }\n\n    long long remaining_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n            deadline - chrono::steady_clock::now()\n        ).count();\n    }\n\n    static bool betterMove(const Move& a, const Move& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.parDepth != b.parDepth) return a.parDepth > b.parDepth;\n        if (a.parentA != b.parentA) return a.parentA < b.parentA;\n        if (a.parentSub != b.parentSub) return a.parentSub < b.parentSub;\n        if (a.parentDeg != b.parentDeg) return a.parentDeg > b.parentDeg;\n        if (a.childSub != b.childSub) return a.childSub > b.childSub;\n        if (a.child != b.child) return a.child < b.child;\n        return a.par < b.par;\n    }\n\n    static bool betterDMove(const DMove& a, const DMove& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.newDepth != b.newDepth) return a.newDepth > b.newDepth;\n        if (a.type != b.type) return a.type < b.type; // prefer raise over swap on tie\n        if (a.upA != b.upA) return a.upA > b.upA;\n        if (a.downA != b.downA) return a.downA < b.downA;\n        if (a.v != b.v) return a.v < b.v;\n        return a.u < b.u;\n    }\n\n    void rebuild(const vector<int>& parent, State& st) {\n        st.children.assign(N, {});\n        st.roots.clear();\n        st.depth.assign(N, 0);\n        st.tin.assign(N, 0);\n        st.tout.assign(N, 0);\n        st.compId.assign(N, -1);\n        st.subtreeBeauty.assign(N, 0);\n        st.maxAbsDepth.assign(N, 0);\n        st.comps.clear();\n        st.score = 1;\n\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] == -1) st.roots.push_back(v);\n            else st.children[parent[v]].push_back(v);\n        }\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v, int comp) -> void {\n            st.compId[v] = comp;\n            st.tin[v] = timer++;\n            st.comps[comp].push_back(v);\n\n            st.subtreeBeauty[v] = A[v];\n            st.maxAbsDepth[v] = st.depth[v];\n            st.score += 1LL * (st.depth[v] + 1) * A[v];\n\n            for (int ch : st.children[v]) {\n                st.depth[ch] = st.depth[v] + 1;\n                self(self, ch, comp);\n                st.subtreeBeauty[v] += st.subtreeBeauty[ch];\n                st.maxAbsDepth[v] = max(st.maxAbsDepth[v], st.maxAbsDepth[ch]);\n            }\n            st.tout[v] = timer;\n        };\n\n        for (int r : st.roots) {\n            st.depth[r] = 0;\n            st.comps.push_back({});\n            dfs(dfs, r, (int)st.comps.size() - 1);\n        }\n    }\n\n    long long calcScore(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.score;\n    }\n\n    vector<int> depthFromParent(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.depth;\n    }\n\n    vector<int> parentFromDepth(const vector<int>& depth) {\n        vector<int> parent(N, -1);\n        vector<vector<int>> layers(H + 1);\n        for (int v = 0; v < N; ++v) layers[depth[v]].push_back(v);\n\n        for (int d = 1; d <= H; ++d) {\n            for (int v : layers[d]) {\n                int best = -1;\n                for (int to : g[v]) if (depth[to] == d - 1) {\n                    if (best == -1) best = to;\n                    else {\n                        if (A[to] != A[best]) best = (A[to] < A[best] ? to : best);\n                        else if (deg[to] != deg[best]) best = (deg[to] > deg[best] ? to : best);\n                        else if (to < best) best = to;\n                    }\n                }\n                if (best == -1) parent[v] = -1; // should not happen if depth is feasible\n                else parent[v] = best;\n            }\n        }\n        return parent;\n    }\n\n    long long scoreDepth(const vector<int>& depth) {\n        long long sc = 1;\n        for (int v = 0; v < N; ++v) sc += 1LL * (depth[v] + 1) * A[v];\n        return sc;\n    }\n\n    bool makeCandidate(int par, int child, const State& st, Move& mv) {\n        int newDepth = st.depth[par] + 1;\n        if (newDepth > H) return false;\n        if (newDepth <= st.depth[child]) return false;\n\n        if (st.compId[par] == st.compId[child]) {\n            if (st.tin[child] <= st.tin[par] && st.tin[par] < st.tout[child]) {\n                return false;\n            }\n        }\n\n        int delta = newDepth - st.depth[child];\n        if (st.maxAbsDepth[child] + delta > H) return false;\n\n        mv.gain = 1LL * delta * st.subtreeBeauty[child];\n        if (mv.gain <= 0) return false;\n\n        mv.par = par;\n        mv.child = child;\n        mv.parentSub = st.subtreeBeauty[par];\n        mv.parDepth = st.depth[par];\n        mv.parentDeg = deg[par];\n        mv.parentA = A[par];\n        mv.childSub = st.subtreeBeauty[child];\n        return true;\n    }\n\n    bool findMoveDeterministic(const State& st, Move& best) {\n        bool found = false;\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool findMoveRandomized(const State& st, Move& chosen) {\n        vector<Move> cand;\n        cand.reserve(2 * M);\n        long long bestGain = 0;\n\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain * 100 >= bestGain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain * 100 >= bestGain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n        }\n\n        if (bestGain <= 0) return false;\n        sort(cand.begin(), cand.end(), betterMove);\n        int k = min<int>(12, cand.size());\n        uniform_int_distribution<int> dist(0, k - 1);\n        chosen = cand[dist(rng)];\n        return true;\n    }\n\n    void hillClimb(vector<int>& parent, bool randomized) {\n        while (!time_up()) {\n            State st;\n            rebuild(parent, st);\n\n            Move mv;\n            bool ok = randomized ? findMoveRandomized(st, mv)\n                                 : findMoveDeterministic(st, mv);\n            if (!ok) break;\n            parent[mv.child] = mv.par;\n        }\n    }\n\n    bool rerootOptimize(vector<int>& parent) {\n        if (time_up()) return false;\n\n        State st;\n        rebuild(parent, st);\n\n        vector<vector<int>> treeAdj(N);\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] != -1) {\n                treeAdj[v].push_back(parent[v]);\n                treeAdj[parent[v]].push_back(v);\n            }\n        }\n\n        vector<int> newParent = parent;\n        bool changedAny = false;\n\n        auto dfsScore = [&](auto&& self, int v, int p, int d, long long& sc, int& mx,\n                            const vector<vector<int>>& adj) -> void {\n            sc += 1LL * A[v] * d;\n            mx = max(mx, d);\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, d + 1, sc, mx, adj);\n            }\n        };\n\n        auto dfsOrient = [&](auto&& self, int v, int p,\n                             vector<int>& par, const vector<vector<int>>& adj) -> void {\n            par[v] = p;\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, par, adj);\n            }\n        };\n\n        for (const auto& comp : st.comps) {\n            if (time_up()) return changedAny;\n            if (comp.size() <= 1) continue;\n\n            long long bestScore = LLONG_MIN;\n            int bestRoot = comp[0];\n\n            for (int r : comp) {\n                long long sc = 0;\n                int mx = 0;\n                dfsScore(dfsScore, r, -1, 0, sc, mx, treeAdj);\n                if (mx > H) continue;\n\n                bool better = false;\n                if (sc > bestScore) better = true;\n                else if (sc == bestScore) {\n                    if (A[r] < A[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] > deg[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] == deg[bestRoot] && r < bestRoot) better = true;\n                }\n                if (better) {\n                    bestScore = sc;\n                    bestRoot = r;\n                }\n            }\n\n            if (bestScore == LLONG_MIN) continue;\n            dfsOrient(dfsOrient, bestRoot, -1, newParent, treeAdj);\n        }\n\n        if (newParent != parent) {\n            parent.swap(newParent);\n            changedAny = true;\n        }\n        return changedAny;\n    }\n\n    // -------- depth-label local search --------\n\n    bool canRaiseVertex(int v, const vector<int>& depth,\n                        const vector<array<int, 11>>& cnt) {\n        int d = depth[v];\n        if (d >= H) return false;\n        if (cnt[v][d] <= 0) return false; // need some neighbor at depth d\n        for (int x : g[v]) {\n            if (depth[x] == d + 1 && cnt[x][d] == 1) return false;\n        }\n        return true;\n    }\n\n    bool canSwapEdge(int v, int u, const vector<int>& depth,\n                     const vector<array<int, 11>>& cnt) {\n        // require depth[v] = d, depth[u] = d+1\n        int d = depth[v];\n        if (d + 1 != depth[u]) return false;\n        if (A[v] <= A[u]) return false; // improving only\n        if (d >= H) return false;\n\n        // u moves to d, so it must have a neighbor at d-1 (unless d==0)\n        if (d > 0 && cnt[u][d - 1] == 0) return false;\n\n        // vertices at depth d+1 neighboring v must keep a depth-d support\n        for (int x : g[v]) {\n            if (x == u) continue;\n            if (depth[x] == d + 1) {\n                int newCnt = cnt[x][d] - 1 + (adjMat[u][x] ? 1 : 0);\n                if (newCnt <= 0) return false;\n            }\n        }\n\n        // vertices at depth d+2 neighboring u must keep a depth-(d+1) support\n        if (d + 2 <= H) {\n            for (int y : g[u]) {\n                if (depth[y] == d + 2) {\n                    int newCnt = cnt[y][d + 1] - 1 + (adjMat[v][y] ? 1 : 0);\n                    if (newCnt <= 0) return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    void applyRaise(int v, vector<int>& depth, vector<array<int, 11>>& cnt) {\n        int d = depth[v];\n        for (int x : g[v]) {\n            cnt[x][d]--;\n            cnt[x][d + 1]++;\n        }\n        depth[v]++;\n    }\n\n    void applySwap(int v, int u, vector<int>& depth, vector<array<int, 11>>& cnt) {\n        // depth[v] = d, depth[u] = d+1\n        int d = depth[v];\n\n        for (int x : g[v]) {\n            cnt[x][d]--;\n            cnt[x][d + 1]++;\n        }\n        for (int x : g[u]) {\n            cnt[x][d + 1]--;\n            cnt[x][d]++;\n        }\n        depth[v]++;\n        depth[u]--;\n    }\n\n    bool findDepthMove(const vector<int>& depth, const vector<array<int, 11>>& cnt,\n                       bool randomized, DMove& chosen) {\n        DMove best;\n        bool found = false;\n        vector<DMove> cand;\n        cand.reserve(N + M);\n\n        auto pushCand = [&](const DMove& mv) {\n            if (!randomized) {\n                if (!found || betterDMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            } else {\n                if (!found || mv.gain > best.gain) {\n                    best = mv;\n                    cand.clear();\n                    cand.push_back(mv);\n                    found = true;\n                } else if (mv.gain * 100 >= best.gain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n        };\n\n        for (int v = 0; v < N; ++v) {\n            if (canRaiseVertex(v, depth, cnt)) {\n                DMove mv;\n                mv.type = 0;\n                mv.v = v;\n                mv.u = -1;\n                mv.gain = A[v];\n                mv.newDepth = depth[v] + 1;\n                mv.upA = A[v];\n                mv.downA = 0;\n                pushCand(mv);\n            }\n        }\n\n        for (auto [a, b] : edges) {\n            if (depth[a] + 1 == depth[b]) {\n                if (canSwapEdge(a, b, depth, cnt)) {\n                    DMove mv;\n                    mv.type = 1;\n                    mv.v = a;\n                    mv.u = b;\n                    mv.gain = A[a] - A[b];\n                    mv.newDepth = depth[a] + 1;\n                    mv.upA = A[a];\n                    mv.downA = A[b];\n                    pushCand(mv);\n                }\n            } else if (depth[b] + 1 == depth[a]) {\n                if (canSwapEdge(b, a, depth, cnt)) {\n                    DMove mv;\n                    mv.type = 1;\n                    mv.v = b;\n                    mv.u = a;\n                    mv.gain = A[b] - A[a];\n                    mv.newDepth = depth[b] + 1;\n                    mv.upA = A[b];\n                    mv.downA = A[a];\n                    pushCand(mv);\n                }\n            }\n        }\n\n        if (!found) return false;\n\n        if (!randomized) {\n            chosen = best;\n            return true;\n        }\n\n        sort(cand.begin(), cand.end(), betterDMove);\n        int k = min<int>(16, cand.size());\n        uniform_int_distribution<int> dist(0, k - 1);\n        chosen = cand[dist(rng)];\n        return true;\n    }\n\n    void depthLocalSearch(vector<int>& depth, bool randomized) {\n        vector<array<int, 11>> cnt(N);\n        for (int v = 0; v < N; ++v) {\n            for (int d = 0; d <= H; ++d) cnt[v][d] = 0;\n        }\n        for (auto [u, v] : edges) {\n            cnt[u][depth[v]]++;\n            cnt[v][depth[u]]++;\n        }\n\n        int iter = 0;\n        while (!time_up() && iter < 6000) {\n            DMove mv;\n            if (!findDepthMove(depth, cnt, randomized, mv)) break;\n            if (mv.type == 0) applyRaise(mv.v, depth, cnt);\n            else applySwap(mv.v, mv.u, depth, cnt);\n            ++iter;\n        }\n    }\n\n    // -------- initializers --------\n\n    vector<int> buildAllRoots() {\n        return vector<int>(N, -1);\n    }\n\n    vector<int> buildFromKey(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n\n        vector<int> parent(N, -1), depth(N, 0);\n        vector<char> done(N, 0);\n\n        auto betterPar = [&](int x, int y) {\n            if (y == -1) return true;\n            if (depth[x] != depth[y]) return depth[x] > depth[y];\n            if (A[x] != A[y]) return A[x] < A[y];\n            if (deg[x] != deg[y]) return deg[x] > deg[y];\n            return x < y;\n        };\n\n        for (int v : ord) {\n            int bestPar = -1;\n            for (int to : g[v]) {\n                if (!done[to]) continue;\n                if (depth[to] >= H) continue;\n                if (betterPar(to, bestPar)) bestPar = to;\n            }\n            if (bestPar != -1) {\n                parent[v] = bestPar;\n                depth[v] = depth[bestPar] + 1;\n            } else {\n                parent[v] = -1;\n                depth[v] = 0;\n            }\n            done[v] = 1;\n        }\n        return parent;\n    }\n\n    vector<int> bfsDist(int s) {\n        const int INF = 1e9;\n        vector<int> dist(N, INF);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (int to : g[v]) {\n                if (dist[to] != INF) continue;\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n        return dist;\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    vector<int> buildBeautyOrder(double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = 1.0 * A[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildBeautyDegreeOrder(double wA, double wDeg, double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = wA * A[v] - wDeg * deg[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildProjectionOrder(double angle, double wA, double wP, double noiseScale = 1e-4) {\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildSeedDistOrder(int seed, double wD, double wA, double angle = 0.0,\n                                   double wP = 0.0, double noiseScale = 1e-4) {\n        auto dist = bfsDist(seed);\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wD * dist[v] + wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> seedCandidates() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            long long da = 1LL * (X[a] - 500) * (X[a] - 500) + 1LL * (Y[a] - 500) * (Y[a] - 500);\n            long long db = 1LL * (X[b] - 500) * (X[b] - 500) + 1LL * (Y[b] - 500) * (Y[b] - 500);\n            double sa = 18.0 * A[a] - 2.5 * deg[a] + 0.002 * sqrt((double)da);\n            double sb = 18.0 * A[b] - 2.5 * deg[b] + 0.002 * sqrt((double)db);\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n        int K = min(16, N);\n        ord.resize(K);\n        return ord;\n    }\n\n    // -------- candidate pipeline --------\n\n    void tryUpdate(const vector<int>& cand, vector<int>& bestParent, long long& bestScore) {\n        long long sc = calcScore(cand);\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestParent = cand;\n        }\n    }\n\n    void processCandidate(vector<int> parent, bool randomizedFirst,\n                          vector<int>& bestParent, long long& bestScore) {\n        if (time_up()) return;\n\n        // Depth-label improvement\n        {\n            vector<int> depth = depthFromParent(parent);\n            depthLocalSearch(depth, randomizedFirst && remaining_ms() > 900);\n            parent = parentFromDepth(depth);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        // Forest polish\n        if (remaining_ms() > 900) {\n            hillClimb(parent, randomizedFirst);\n            if (!time_up()) rerootOptimize(parent);\n            if (!time_up()) hillClimb(parent, false);\n            tryUpdate(parent, bestParent, bestScore);\n        } else if (remaining_ms() > 400) {\n            hillClimb(parent, false);\n            if (!time_up()) rerootOptimize(parent);\n            tryUpdate(parent, bestParent, bestScore);\n        } else {\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        // Depth-label polish again, now from improved forest\n        {\n            vector<int> depth = depthFromParent(parent);\n            depthLocalSearch(depth, false);\n            parent = parentFromDepth(depth);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        if (remaining_ms() > 250) {\n            hillClimb(parent, false);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n    }\n\n    vector<int> solve() {\n        start_time = chrono::steady_clock::now();\n        deadline = start_time + chrono::milliseconds(1900);\n\n        vector<int> bestParent = buildAllRoots();\n        long long bestScore = calcScore(bestParent);\n\n        auto seeds = seedCandidates();\n\n        // Deterministic / semi-deterministic starts\n        processCandidate(buildAllRoots(), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyOrder(), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyDegreeOrder(1.0, 1.5), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyDegreeOrder(1.6, 2.0), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        const vector<double> fixedAngles = {\n            0.0,\n            acos(-1.0) / 4.0,\n            acos(-1.0) / 2.0,\n            3.0 * acos(-1.0) / 4.0\n        };\n        for (double ang : fixedAngles) {\n            if (time_up()) break;\n            processCandidate(buildProjectionOrder(ang, 1.3, 0.05), true, bestParent, bestScore);\n        }\n\n        for (int i = 0; i < (int)seeds.size() && i < 4 && !time_up(); ++i) {\n            int s = seeds[i];\n            double ang = 2.0 * acos(-1.0) * (i + 1) / 7.0;\n            processCandidate(buildSeedDistOrder(s, 10.0, 1.0, ang, 0.015), true, bestParent, bestScore);\n            if (time_up()) break;\n            processCandidate(buildSeedDistOrder(s, 14.0, 0.8, ang, 0.0), true, bestParent, bestScore);\n        }\n\n        // Randomized multi-start\n        int trial = 0;\n        while (!time_up()) {\n            vector<int> p;\n            int typ = trial % 5;\n\n            if (typ == 0) {\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wA = 0.8 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.08;\n                p = buildProjectionOrder(ang, wA, wP, 1e-3);\n            } else if (typ == 1) {\n                int s = seeds[uniform_int_distribution<int>(0, (int)seeds.size() - 1)(rng)];\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wD = 7.0 + 10.0 * rand01();\n                double wA = 0.6 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.03;\n                p = buildSeedDistOrder(s, wD, wA, ang, wP, 1e-3);\n            } else if (typ == 2) {\n                double wA = 0.8 + 1.2 * rand01();\n                double wDeg = 0.5 + 2.5 * rand01();\n                p = buildBeautyDegreeOrder(wA, wDeg, 1e-3);\n            } else if (typ == 3) {\n                p = buildBeautyOrder(1e-3);\n            } else {\n                p = buildAllRoots();\n            }\n\n            processCandidate(p, remaining_ms() > 700, bestParent, bestScore);\n            ++trial;\n        }\n\n        return bestParent;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M >> solver.H;\n    solver.A.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.A[i];\n\n    solver.edges.resize(solver.M);\n    solver.g.assign(solver.N, {});\n    solver.deg.assign(solver.N, 0);\n    solver.adjMat.assign(solver.N, {});\n\n    for (int i = 0; i < solver.M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        solver.edges[i] = {u, v};\n        solver.g[u].push_back(v);\n        solver.g[v].push_back(u);\n        solver.deg[u]++;\n        solver.deg[v]++;\n        solver.adjMat[u].set(v);\n        solver.adjMat[v].set(u);\n    }\n\n    solver.X.resize(solver.N);\n    solver.Y.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) {\n        cin >> solver.X[i] >> solver.Y[i];\n    }\n\n    vector<int> ans = solver.solve();\n\n    for (int i = 0; i < solver.N; ++i) {\n        if (i) cout << ' ';\n        cout << ans[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAX_ONI = 40;\nstatic constexpr int SIDE = 80;\nstatic constexpr int MAXD = 20;\nstatic constexpr int MAXP = 32;\nstatic constexpr double TL = 1.92;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n} timer_;\n\nmt19937_64 rng_(1);\n\ninline int sideL(int r) { return r; }\ninline int sideR(int r) { return 20 + r; }\ninline int sideU(int c) { return 40 + c; }\ninline int sideD(int c) { return 60 + c; }\n\ninline char sideDir(int s) {\n    if (s < 20) return 'L';\n    if (s < 40) return 'R';\n    if (s < 60) return 'U';\n    return 'D';\n}\ninline int sideIdx(int s) {\n    if (s < 20) return s;\n    if (s < 40) return s - 20;\n    if (s < 60) return s - 40;\n    return s - 60;\n}\ninline char revDir(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\nstruct Macro {\n    char d;\n    int p;\n    int k;\n};\n\ninline int macroSide(const Macro& a) {\n    if (a.d == 'L') return sideL(a.p);\n    if (a.d == 'R') return sideR(a.p);\n    if (a.d == 'U') return sideU(a.p);\n    return sideD(a.p);\n}\n\nstruct Board {\n    array<array<char, N>, N> g{};\n    int xcnt = 0;\n};\n\nstruct FinishData {\n    int m = 0;\n    bool safe = true;\n    array<pair<int,int>, MAX_ONI> pos{};\n    array<array<int, 4>, MAX_ONI> candList{};\n    array<int, MAX_ONI> candCnt{};\n    array<array<int, SIDE>, MAX_ONI> depthOf{};\n    array<int, MAX_ONI> minDepth{};\n    array<int, N> firstORow{}, lastORow{}, firstOCol{}, lastOCol{};\n};\n\nstruct State {\n    array<int, MAX_ONI> assign{};\n    array<array<unsigned char, MAXD + 1>, SIDE> cnt{};\n    array<int, SIDE> dep{};\n    array<unsigned long long, SIDE> mem{};\n    int S = 0;\n    int M = 0;\n    int cost() const { return S - M; }\n};\n\nstruct BeamNode {\n    Board b;\n    array<Macro, MAXP> pref{};\n    int plen = 0;\n    int prefixCost = 0;\n    int est = (int)1e9;\n    uint64_t h = 0;\n};\n\nstruct Endpoint {\n    Board b;\n    array<Macro, MAXP> pref{};\n    int plen = 0;\n    int prefixCost = 0;\n    int quickTotal = (int)1e9;\n    uint64_t h = 0;\n};\n\nuint64_t hashBoard(const Board& b) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            h ^= (uint64_t)(unsigned char)b.g[i][j];\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nvoid applyOne(Board& b, char d, int p) {\n    if (d == 'L') {\n        if (b.g[p][0] == 'x') b.xcnt--;\n        for (int j = 0; j + 1 < N; j++) b.g[p][j] = b.g[p][j + 1];\n        b.g[p][N - 1] = '.';\n    } else if (d == 'R') {\n        if (b.g[p][N - 1] == 'x') b.xcnt--;\n        for (int j = N - 1; j >= 1; j--) b.g[p][j] = b.g[p][j - 1];\n        b.g[p][0] = '.';\n    } else if (d == 'U') {\n        if (b.g[0][p] == 'x') b.xcnt--;\n        for (int i = 0; i + 1 < N; i++) b.g[i][p] = b.g[i + 1][p];\n        b.g[N - 1][p] = '.';\n    } else {\n        if (b.g[N - 1][p] == 'x') b.xcnt--;\n        for (int i = N - 1; i >= 1; i--) b.g[i][p] = b.g[i - 1][p];\n        b.g[0][p] = '.';\n    }\n}\n\nvoid applyMacro(Board& b, const Macro& a) {\n    for (int t = 0; t < a.k; t++) applyOne(b, a.d, a.p);\n}\n\nFinishData buildData(const Board& b) {\n    FinishData D;\n    for (int i = 0; i < N; i++) {\n        D.firstORow[i] = N;\n        D.lastORow[i] = -1;\n    }\n    for (int j = 0; j < N; j++) {\n        D.firstOCol[j] = N;\n        D.lastOCol[j] = -1;\n    }\n\n    D.m = 0;\n    D.safe = true;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] == 'o') {\n                D.firstORow[i] = min(D.firstORow[i], j);\n                D.lastORow[i] = max(D.lastORow[i], j);\n                D.firstOCol[j] = min(D.firstOCol[j], i);\n                D.lastOCol[j] = max(D.lastOCol[j], i);\n            }\n        }\n    }\n\n    for (int u = 0; u < MAX_ONI; u++) {\n        D.candCnt[u] = 0;\n        D.minDepth[u] = 1e9;\n        D.depthOf[u].fill(0);\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] != 'x') continue;\n            int u = D.m++;\n            D.pos[u] = {i, j};\n\n            auto addCand = [&](int s, int d) {\n                int c = D.candCnt[u];\n                D.candList[u][c] = s;\n                D.candCnt[u]++;\n                D.depthOf[u][s] = d;\n                D.minDepth[u] = min(D.minDepth[u], d);\n            };\n\n            if (j < D.firstORow[i]) addCand(sideL(i), j + 1);\n            if (j > D.lastORow[i]) addCand(sideR(i), N - j);\n            if (i < D.firstOCol[j]) addCand(sideU(j), i + 1);\n            if (i > D.lastOCol[j]) addCand(sideD(j), N - i);\n\n            if (D.candCnt[u] == 0) D.safe = false;\n        }\n    }\n    return D;\n}\n\nState emptyState() {\n    State st;\n    st.assign.fill(-1);\n    for (int s = 0; s < SIDE; s++) {\n        st.cnt[s].fill(0);\n        st.dep[s] = 0;\n        st.mem[s] = 0ULL;\n    }\n    st.S = 0;\n    st.M = 0;\n    return st;\n}\n\ninline int recomputeM(const State& st) {\n    int m = 0;\n    for (int s = 0; s < SIDE; s++) m = max(m, st.dep[s]);\n    return m;\n}\n\nvoid addAssign(State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    st.assign[u] = s;\n    st.mem[s] |= (1ULL << u);\n    st.cnt[s][d]++;\n    if (d > st.dep[s]) {\n        st.S += 2 * (d - st.dep[s]);\n        st.dep[s] = d;\n    }\n    if (st.dep[s] > st.M) st.M = st.dep[s];\n}\n\nvoid removeAssign(State& st, const FinishData& D, int u) {\n    int s = st.assign[u];\n    if (s < 0) return;\n    int d = D.depthOf[u][s];\n    st.assign[u] = -1;\n    st.mem[s] &= ~(1ULL << u);\n    st.cnt[s][d]--;\n    if (d == st.dep[s] && st.cnt[s][d] == 0) {\n        int nd = st.dep[s];\n        while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n        st.S += 2 * (nd - st.dep[s]);\n        st.dep[s] = nd;\n    }\n    st.M = recomputeM(st);\n}\n\ninline int secondDepthAfterRemoving(const State& st, int s, int remDepth) {\n    if (remDepth != st.dep[s]) return st.dep[s];\n    if (st.cnt[s][remDepth] >= 2) return st.dep[s];\n    int nd = st.dep[s] - 1;\n    while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n    return nd;\n}\n\nint evalAdd(const State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    int nd = max(st.dep[s], d);\n    int newS = st.S + 2 * (nd - st.dep[s]);\n    int newM = max(st.M, nd);\n    return newS - newM;\n}\n\nint evalMove(const State& st, const FinishData& D, int u, int ns) {\n    int os = st.assign[u];\n    if (os == ns) return st.cost();\n\n    int od = D.depthOf[u][os];\n    int nd = D.depthOf[u][ns];\n    int depOldAfter = secondDepthAfterRemoving(st, os, od);\n    int depNewAfter = max(st.dep[ns], nd);\n\n    int newS = st.S + 2 * (depOldAfter - st.dep[os]) + 2 * (depNewAfter - st.dep[ns]);\n\n    int newM = 0;\n    for (int s = 0; s < SIDE; s++) {\n        int d = st.dep[s];\n        if (s == os) d = depOldAfter;\n        else if (s == ns) d = depNewAfter;\n        newM = max(newM, d);\n    }\n    return newS - newM;\n}\n\nvector<int> makeOrderDifficulty(const FinishData& D, bool randomized) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    vector<uint64_t> key(D.m);\n    for (int i = 0; i < D.m; i++) key[i] = rng_();\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D.candCnt[a] != D.candCnt[b]) return D.candCnt[a] < D.candCnt[b];\n        if (D.minDepth[a] != D.minDepth[b]) return D.minDepth[a] > D.minDepth[b];\n        if (randomized) return key[a] < key[b];\n        return a < b;\n    });\n    return ord;\n}\n\nvector<int> makeOrderRandom(int m) {\n    vector<int> ord(m);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng_);\n    return ord;\n}\n\nState buildGreedy(const FinishData& D, const vector<int>& ord, bool randomized) {\n    State st = emptyState();\n    for (int u : ord) {\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            opts[oc++] = {evalAdd(st, D, u, s), s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        int choose = opts[0].second;\n        if (randomized && oc > 1) {\n            int lim = 1;\n            while (lim < oc && opts[lim].first <= opts[0].first + 1) ++lim;\n            lim = min(lim, 3);\n            choose = opts[(int)(rng_() % lim)].second;\n        }\n        addAssign(st, D, u, choose);\n    }\n    return st;\n}\n\nState buildMinDepthState(const FinishData& D) {\n    State st = emptyState();\n    for (int u = 0; u < D.m; u++) {\n        int bestS = D.candList[u][0];\n        int bestD = D.depthOf[u][bestS];\n        for (int it = 1; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            int d = D.depthOf[u][s];\n            if (d < bestD || (d == bestD && s < bestS)) {\n                bestD = d;\n                bestS = s;\n            }\n        }\n        addAssign(st, D, u, bestS);\n    }\n    return st;\n}\n\nvoid local1(const FinishData& D, State& st, int rounds = 2) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    for (int rep = 0; rep < rounds; rep++) {\n        bool improved = false;\n        for (int u : ord) {\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvector<int> membersOfMask(unsigned long long mask) {\n    vector<int> res;\n    while (mask) {\n        int b = __builtin_ctzll(mask);\n        res.push_back(b);\n        mask &= mask - 1;\n    }\n    return res;\n}\n\nbool exactReoptSubset(State& st, const FinishData& D, vector<int> subset, int forbidSide, double deadline) {\n    if (subset.empty()) return false;\n\n    State original = st;\n    for (int u : subset) removeAssign(st, D, u);\n\n    for (int u : subset) {\n        int ok = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != forbidSide) ok++;\n        }\n        if (ok == 0) {\n            st = original;\n            return false;\n        }\n    }\n\n    sort(subset.begin(), subset.end(), [&](int a, int b) {\n        int ca = 0, cb = 0;\n        for (int it = 0; it < D.candCnt[a]; it++) if (D.candList[a][it] != forbidSide) ca++;\n        for (int it = 0; it < D.candCnt[b]; it++) if (D.candList[b][it] != forbidSide) cb++;\n        if (ca != cb) return ca < cb;\n        return D.minDepth[a] > D.minDepth[b];\n    });\n\n    int bestCost = original.cost();\n    State bestState = original;\n    long long nodes = 0;\n    bool timeout = false;\n\n    function<void(int)> dfs = [&](int idx) {\n        if ((nodes++ & 1023LL) == 0 && timer_.elapsed() >= deadline) {\n            timeout = true;\n            return;\n        }\n        int curCost = st.cost();\n        if (curCost >= bestCost) return;\n        if (idx == (int)subset.size()) {\n            bestCost = curCost;\n            bestState = st;\n            return;\n        }\n\n        int u = subset[idx];\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            if (s == forbidSide) continue;\n            int c = evalAdd(st, D, u, s);\n            if (c < bestCost) opts[oc++] = {c, s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        for (int i = 0; i < oc; i++) {\n            int s = opts[i].second;\n            int c = opts[i].first;\n            if (c >= bestCost) break;\n            addAssign(st, D, u, s);\n            dfs(idx + 1);\n            removeAssign(st, D, u);\n            if (timeout) return;\n        }\n    };\n\n    dfs(0);\n    st = bestState;\n    return st.cost() < original.cost();\n}\n\nbool exactCloseOneSide(State& st, const FinishData& D, int side, double deadline) {\n    int sz = __builtin_popcountll(st.mem[side]);\n    if (sz <= 1 || sz > 8) return false;\n    vector<int> subset = membersOfMask(st.mem[side]);\n    for (int u : subset) {\n        bool alt = false;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != side) { alt = true; break; }\n        }\n        if (!alt) return false;\n    }\n    return exactReoptSubset(st, D, subset, side, deadline);\n}\n\nvoid localImproveLight(const FinishData& D, State& st, double deadline) {\n    while (timer_.elapsed() < deadline) {\n        bool improved = false;\n        vector<int> ord(D.m);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng_);\n\n        for (int u : ord) {\n            if (timer_.elapsed() >= deadline) return;\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvoid localImproveStrong(const FinishData& D, State& st, double deadline) {\n    while (timer_.elapsed() < deadline) {\n        bool improved = false;\n\n        vector<int> ord(D.m);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng_);\n\n        for (int u : ord) {\n            if (timer_.elapsed() >= deadline) return;\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        vector<int> sides;\n        for (int s = 0; s < SIDE; s++) {\n            int sz = __builtin_popcountll(st.mem[s]);\n            if (sz >= 2 && sz <= 8) sides.push_back(s);\n        }\n        shuffle(sides.begin(), sides.end(), rng_);\n\n        for (int s : sides) {\n            if (timer_.elapsed() >= deadline) return;\n            if (exactCloseOneSide(st, D, s, deadline)) {\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nState quickSolve(const FinishData& D) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    State best = buildGreedy(D, makeOrderDifficulty(D, false), false);\n    local1(D, best, 2);\n\n    State alt = buildMinDepthState(D);\n    local1(D, alt, 2);\n    if (alt.cost() < best.cost()) best = alt;\n\n    return best;\n}\n\nState strongSolve(const FinishData& D, double deadline) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    double start = timer_.elapsed();\n    double total = deadline - start;\n\n    State best = quickSolve(D);\n\n    if (total <= 0.003) return best;\n\n    // Initial improvement on the deterministic baseline.\n    {\n        double rem = deadline - timer_.elapsed();\n        double slice = min(rem, (rem >= 0.03 ? 0.014 : 0.006));\n        if (slice > 0.0) {\n            double endt = timer_.elapsed() + slice;\n            if (slice >= 0.010) localImproveStrong(D, best, endt);\n            else localImproveLight(D, best, endt);\n        }\n    }\n\n    int iter = 0;\n    while (timer_.elapsed() < deadline) {\n        double rem = deadline - timer_.elapsed();\n        if (rem <= 0.001) break;\n\n        State st;\n        if (iter % 3 == 0) st = buildGreedy(D, makeOrderDifficulty(D, true), true);\n        else if (iter % 3 == 1) st = buildGreedy(D, makeOrderRandom(D.m), true);\n        else st = buildMinDepthState(D);\n\n        double slice = min(rem, rem >= 0.03 ? 0.012 : (rem >= 0.012 ? 0.007 : rem));\n        double endt = timer_.elapsed() + slice;\n\n        if (slice >= 0.010) localImproveStrong(D, st, endt);\n        else localImproveLight(D, st, endt);\n\n        if (st.cost() < best.cost()) best = st;\n        iter++;\n    }\n    return best;\n}\n\nvoid emitSide(vector<pair<char,int>>& ops, int side, int depth, bool restore) {\n    char d = sideDir(side);\n    char rd = revDir(d);\n    int p = sideIdx(side);\n    for (int t = 0; t < depth; t++) ops.push_back({d, p});\n    if (restore) {\n        for (int t = 0; t < depth; t++) ops.push_back({rd, p});\n    }\n}\n\nvector<pair<char,int>> buildFinishOps(const State& st) {\n    vector<int> used;\n    for (int s = 0; s < SIDE; s++) if (st.dep[s] > 0) used.push_back(s);\n    vector<pair<char,int>> ops;\n    if (used.empty()) return ops;\n\n    int finalSide = used[0];\n    for (int s : used) {\n        if (st.dep[s] > st.dep[finalSide]) finalSide = s;\n    }\n\n    sort(used.begin(), used.end(), [&](int a, int b) {\n        if (st.dep[a] != st.dep[b]) return st.dep[a] < st.dep[b];\n        return a < b;\n    });\n\n    for (int s : used) {\n        if (s == finalSide) continue;\n        emitSide(ops, s, st.dep[s], true);\n    }\n    emitSide(ops, finalSide, st.dep[finalSide], false);\n    return ops;\n}\n\nvector<pair<char,int>> buildPlan(const array<Macro, MAXP>& pref, int plen, const State& st) {\n    vector<pair<char,int>> ops;\n    for (int i = 0; i < plen; i++) {\n        for (int t = 0; t < pref[i].k; t++) ops.push_back({pref[i].d, pref[i].p});\n    }\n    auto fin = buildFinishOps(st);\n    ops.insert(ops.end(), fin.begin(), fin.end());\n    return ops;\n}\n\npair<int,int> simulate(const Board& init, const vector<pair<char,int>>& ops) {\n    Board b = init;\n    int removedO = 0;\n    for (auto [d, p] : ops) {\n        if (d == 'L') {\n            if (b.g[p][0] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'R') {\n            if (b.g[p][N - 1] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'U') {\n            if (b.g[0][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else {\n            if (b.g[N - 1][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        }\n    }\n    return {b.xcnt, removedO};\n}\n\nstruct ScoredAction {\n    Macro a;\n    int score;\n};\n\nvector<Macro> enumerateActions(const Board& b, const FinishData& D, int cap = 80) {\n    array<int, N> rowX{}, colX{};\n    for (int i = 0; i < N; i++) rowX[i] = 0;\n    for (int j = 0; j < N; j++) colX[j] = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] == 'x') {\n                rowX[i]++;\n                colX[j]++;\n            }\n        }\n    }\n\n    bool seen[SIDE][MAXD + 1];\n    for (int s = 0; s < SIDE; s++) for (int d = 0; d <= MAXD; d++) seen[s][d] = false;\n\n    vector<ScoredAction> ret;\n    ret.reserve(320);\n\n    auto pushAct = [&](Macro a, int score) {\n        if (a.k <= 0 || a.k > 20) return;\n        int s = macroSide(a);\n        if (seen[s][a.k]) return;\n        seen[s][a.k] = true;\n        ret.push_back({a, score});\n    };\n\n    for (int r = 0; r < N; r++) {\n        int limL = D.firstORow[r];\n        int removed = 0;\n        bool hasXSafe = false;\n        for (int j = 0; j < limL; j++) {\n            if (b.g[r][j] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'L', r, j + 1}, 260 * removed - 10 * (j + 1));\n            }\n        }\n        if (rowX[r] > 0) {\n            if (limL > 1) pushAct({'L', r, limL}, (hasXSafe ? 7 : 22) * rowX[r] - 5 * limL);\n            if (limL >= 2) pushAct({'L', r, 2}, (hasXSafe ? 10 : 16) * rowX[r] - 7);\n            if (limL >= 3) pushAct({'L', r, 3}, (hasXSafe ? 8 : 12) * rowX[r] - 10);\n        }\n\n        int limR = (D.lastORow[r] == -1 ? N : N - 1 - D.lastORow[r]);\n        removed = 0;\n        hasXSafe = false;\n        for (int j = N - 1; j >= N - limR; j--) {\n            if (b.g[r][j] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'R', r, N - j}, 260 * removed - 10 * (N - j));\n            }\n        }\n        if (rowX[r] > 0) {\n            if (limR > 1) pushAct({'R', r, limR}, (hasXSafe ? 7 : 22) * rowX[r] - 5 * limR);\n            if (limR >= 2) pushAct({'R', r, 2}, (hasXSafe ? 10 : 16) * rowX[r] - 7);\n            if (limR >= 3) pushAct({'R', r, 3}, (hasXSafe ? 8 : 12) * rowX[r] - 10);\n        }\n    }\n\n    for (int c = 0; c < N; c++) {\n        int limU = D.firstOCol[c];\n        int removed = 0;\n        bool hasXSafe = false;\n        for (int i = 0; i < limU; i++) {\n            if (b.g[i][c] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'U', c, i + 1}, 260 * removed - 10 * (i + 1));\n            }\n        }\n        if (colX[c] > 0) {\n            if (limU > 1) pushAct({'U', c, limU}, (hasXSafe ? 7 : 22) * colX[c] - 5 * limU);\n            if (limU >= 2) pushAct({'U', c, 2}, (hasXSafe ? 10 : 16) * colX[c] - 7);\n            if (limU >= 3) pushAct({'U', c, 3}, (hasXSafe ? 8 : 12) * colX[c] - 10);\n        }\n\n        int limD = (D.lastOCol[c] == -1 ? N : N - 1 - D.lastOCol[c]);\n        removed = 0;\n        hasXSafe = false;\n        for (int i = N - 1; i >= N - limD; i--) {\n            if (b.g[i][c] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'D', c, N - i}, 260 * removed - 10 * (N - i));\n            }\n        }\n        if (colX[c] > 0) {\n            if (limD > 1) pushAct({'D', c, limD}, (hasXSafe ? 7 : 22) * colX[c] - 5 * limD);\n            if (limD >= 2) pushAct({'D', c, 2}, (hasXSafe ? 10 : 16) * colX[c] - 7);\n            if (limD >= 3) pushAct({'D', c, 3}, (hasXSafe ? 8 : 12) * colX[c] - 10);\n        }\n    }\n\n    for (int r = 0; r < N; r++) {\n        if (rowX[r] > 0) {\n            if (b.g[r][0] != 'o') pushAct({'L', r, 1}, 14 * rowX[r] - 4);\n            if (b.g[r][N - 1] != 'o') pushAct({'R', r, 1}, 14 * rowX[r] - 4);\n        }\n    }\n    for (int c = 0; c < N; c++) {\n        if (colX[c] > 0) {\n            if (b.g[0][c] != 'o') pushAct({'U', c, 1}, 14 * colX[c] - 4);\n            if (b.g[N - 1][c] != 'o') pushAct({'D', c, 1}, 14 * colX[c] - 4);\n        }\n    }\n\n    sort(ret.begin(), ret.end(), [&](const ScoredAction& A, const ScoredAction& B) {\n        if (A.score != B.score) return A.score > B.score;\n        if (A.a.k != B.a.k) return A.a.k < B.a.k;\n        if (A.a.d != B.a.d) return A.a.d < B.a.d;\n        return A.a.p < B.a.p;\n    });\n\n    if ((int)ret.size() > cap) ret.resize(cap);\n    vector<Macro> acts;\n    acts.reserve(ret.size());\n    for (auto& x : ret) acts.push_back(x.a);\n    return acts;\n}\n\nvoid addEndpoint(vector<Endpoint>& eps, const Endpoint& e, int keep = 48) {\n    for (auto& x : eps) {\n        if (x.h == e.h) {\n            if (e.quickTotal < x.quickTotal ||\n                (e.quickTotal == x.quickTotal && e.prefixCost < x.prefixCost) ||\n                (e.quickTotal == x.quickTotal && e.prefixCost == x.prefixCost && e.b.xcnt < x.b.xcnt)) {\n                x = e;\n            }\n            return;\n        }\n    }\n    eps.push_back(e);\n    sort(eps.begin(), eps.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n        return a.b.xcnt < b.b.xcnt;\n    });\n    if ((int)eps.size() > keep) eps.resize(keep);\n}\n\nEndpoint greedyDescendEndpoint(Endpoint ep, int maxSteps, double deadline) {\n    for (int step = 0; step < maxSteps && timer_.elapsed() < deadline; step++) {\n        FinishData D = buildData(ep.b);\n        if (!D.safe) break;\n        State curSt = quickSolve(D);\n        int curTotal = ep.prefixCost + curSt.cost();\n\n        auto acts = enumerateActions(ep.b, D, 32);\n        int bestTotal = curTotal;\n        int bestX = ep.b.xcnt;\n        bool found = false;\n        Macro bestA{};\n        Board bestB;\n\n        for (const auto& a : acts) {\n            if (timer_.elapsed() >= deadline) break;\n            if (ep.plen >= MAXP) break;\n            if (ep.prefixCost + a.k >= 4 * N * N) continue;\n\n            Board nb = ep.b;\n            applyMacro(nb, a);\n            FinishData ND = buildData(nb);\n            if (!ND.safe) continue;\n\n            State qst = quickSolve(ND);\n            int total = ep.prefixCost + a.k + qst.cost();\n\n            if (total < bestTotal || (total == bestTotal && nb.xcnt < bestX)) {\n                bestTotal = total;\n                bestX = nb.xcnt;\n                bestA = a;\n                bestB = nb;\n                found = true;\n            }\n        }\n\n        if (!found) break;\n        ep.b = bestB;\n        ep.pref[ep.plen++] = bestA;\n        ep.prefixCost += bestA.k;\n        ep.quickTotal = bestTotal;\n        ep.h = hashBoard(ep.b);\n    }\n    return ep;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n_in;\n    cin >> n_in;\n\n    Board init;\n    init.xcnt = 0;\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) {\n            init.g[i][j] = s[j];\n            if (s[j] == 'x') init.xcnt++;\n        }\n    }\n\n    uint64_t seed = hashBoard(init) ^ 0x9e3779b97f4a7c15ULL;\n    rng_.seed(seed);\n\n    vector<pair<char,int>> bestOps;\n    int bestLen = (int)1e9;\n\n    FinishData D0 = buildData(init);\n    if (D0.safe) {\n        State q0 = quickSolve(D0);\n        auto ops = buildFinishOps(q0);\n        auto [rx, ry] = simulate(init, ops);\n        if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) {\n            bestOps = ops;\n            bestLen = (int)ops.size();\n        }\n\n        double baseBudget = min(0.10, TL * 0.06);\n        State s0 = strongSolve(D0, min(TL - 0.05, timer_.elapsed() + baseBudget));\n        auto ops2 = buildFinishOps(s0);\n        auto [rx2, ry2] = simulate(init, ops2);\n        if ((int)ops2.size() <= 4 * N * N && rx2 == 0 && ry2 == 0) {\n            if ((int)ops2.size() < bestLen) {\n                bestOps = ops2;\n                bestLen = (int)ops2.size();\n            }\n        }\n    }\n\n    vector<Endpoint> endpoints;\n    {\n        Endpoint ep;\n        ep.b = init;\n        ep.plen = 0;\n        ep.prefixCost = 0;\n        ep.quickTotal = bestLen;\n        ep.h = hashBoard(init);\n        addEndpoint(endpoints, ep, 48);\n    }\n\n    vector<BeamNode> beam;\n    {\n        BeamNode st;\n        st.b = init;\n        st.plen = 0;\n        st.prefixCost = 0;\n        st.est = bestLen;\n        st.h = hashBoard(init);\n        beam.push_back(st);\n    }\n\n    unordered_map<uint64_t, int> bestPrefixCost;\n    bestPrefixCost.reserve(1 << 15);\n    bestPrefixCost[hashBoard(init)] = 0;\n\n    const int BEAM_WIDTH = 24;\n    const int BEAM_DEPTH = 18;\n    double beamEnd = 1.45;\n\n    for (int dep = 0; dep < BEAM_DEPTH && timer_.elapsed() < beamEnd && !beam.empty(); dep++) {\n        vector<BeamNode> cand;\n        cand.reserve(BEAM_WIDTH * 100);\n\n        for (const auto& node : beam) {\n            if (timer_.elapsed() >= beamEnd) break;\n            FinishData D = buildData(node.b);\n            if (!D.safe) continue;\n\n            auto acts = enumerateActions(node.b, D, 80);\n\n            for (const auto& a : acts) {\n                if (timer_.elapsed() >= beamEnd) break;\n                if (node.plen >= MAXP) continue;\n\n                BeamNode child = node;\n                applyMacro(child.b, a);\n                child.pref[child.plen++] = a;\n                child.prefixCost += a.k;\n                if (child.prefixCost >= 4 * N * N) continue;\n\n                child.h = hashBoard(child.b);\n                auto it = bestPrefixCost.find(child.h);\n                if (it != bestPrefixCost.end() && it->second <= child.prefixCost) continue;\n\n                FinishData ND = buildData(child.b);\n                if (!ND.safe) continue;\n\n                State qst = quickSolve(ND);\n                child.est = child.prefixCost + qst.cost();\n\n                auto it2 = bestPrefixCost.find(child.h);\n                if (it2 == bestPrefixCost.end() || child.prefixCost < it2->second) {\n                    bestPrefixCost[child.h] = child.prefixCost;\n                }\n\n                if (child.est < bestLen) {\n                    auto ops3 = buildPlan(child.pref, child.plen, qst);\n                    auto [rx3, ry3] = simulate(init, ops3);\n                    if ((int)ops3.size() <= 4 * N * N && rx3 == 0 && ry3 == 0) {\n                        bestLen = (int)ops3.size();\n                        bestOps = std::move(ops3);\n                    }\n                }\n\n                Endpoint ep;\n                ep.b = child.b;\n                ep.pref = child.pref;\n                ep.plen = child.plen;\n                ep.prefixCost = child.prefixCost;\n                ep.quickTotal = child.est;\n                ep.h = child.h;\n                addEndpoint(endpoints, ep, 48);\n\n                cand.push_back(std::move(child));\n            }\n        }\n\n        vector<BeamNode> nxt;\n        nxt.reserve(BEAM_WIDTH);\n        unordered_set<uint64_t> used;\n        used.reserve(BEAM_WIDTH * 8);\n\n        auto add_from_sorted = [&](auto cmp, int limit) {\n            sort(cand.begin(), cand.end(), cmp);\n            for (auto& x : cand) {\n                if ((int)nxt.size() >= limit) break;\n                if (used.insert(x.h).second) nxt.push_back(x);\n            }\n        };\n\n        add_from_sorted([&](const BeamNode& a, const BeamNode& b) {\n            if (a.est != b.est) return a.est < b.est;\n            if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n            if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n            return a.plen < b.plen;\n        }, 14);\n\n        add_from_sorted([&](const BeamNode& a, const BeamNode& b) {\n            if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n            if (a.est != b.est) return a.est < b.est;\n            if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n            return a.plen < b.plen;\n        }, 20);\n\n        add_from_sorted([&](const BeamNode& a, const BeamNode& b) {\n            if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n            if (a.est != b.est) return a.est < b.est;\n            return a.b.xcnt < b.b.xcnt;\n        }, BEAM_WIDTH);\n\n        if ((int)nxt.size() < BEAM_WIDTH && !cand.empty()) {\n            shuffle(cand.begin(), cand.end(), rng_);\n            for (auto& x : cand) {\n                if ((int)nxt.size() >= BEAM_WIDTH) break;\n                if (used.insert(x.h).second) nxt.push_back(x);\n            }\n        }\n\n        beam.swap(nxt);\n    }\n\n    sort(endpoints.begin(), endpoints.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n        return a.b.xcnt < b.b.xcnt;\n    });\n\n    int improveCnt = min<int>(10, endpoints.size());\n    for (int i = 0; i < improveCnt && timer_.elapsed() < 1.63; i++) {\n        Endpoint imp = greedyDescendEndpoint(endpoints[i], 8, 1.63);\n        addEndpoint(endpoints, imp, 48);\n    }\n\n    sort(endpoints.begin(), endpoints.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n        return a.b.xcnt < b.b.xcnt;\n    });\n\n    for (int i = 0; i < (int)endpoints.size(); i++) {\n        if (timer_.elapsed() >= TL - 0.03) break;\n\n        double remain = TL - 0.02 - timer_.elapsed();\n        int left = (int)endpoints.size() - i;\n        double budget = min(0.11, max(0.022, remain / max(1, left)));\n\n        FinishData D = buildData(endpoints[i].b);\n        if (!D.safe) continue;\n\n        State st = strongSolve(D, min(TL - 0.02, timer_.elapsed() + budget));\n        int total = endpoints[i].prefixCost + st.cost();\n        if (total >= bestLen) continue;\n\n        auto ops4 = buildPlan(endpoints[i].pref, endpoints[i].plen, st);\n        auto [rx4, ry4] = simulate(init, ops4);\n        if ((int)ops4.size() <= 4 * N * N && rx4 == 0 && ry4 == 0) {\n            if ((int)ops4.size() < bestLen) {\n                bestLen = (int)ops4.size();\n                bestOps = std::move(ops4);\n            }\n        }\n    }\n\n    if (bestOps.empty()) {\n        FinishData D = buildData(init);\n        State st = quickSolve(D);\n        bestOps = buildFinishOps(st);\n    } else {\n        auto [rx, ry] = simulate(init, bestOps);\n        if (!((int)bestOps.size() <= 4 * N * N && rx == 0 && ry == 0)) {\n            FinishData D = buildData(init);\n            State st = quickSolve(D);\n            auto ops = buildFinishOps(st);\n            auto [rx2, ry2] = simulate(init, ops);\n            if ((int)ops.size() <= 4 * N * N && rx2 == 0 && ry2 == 0) bestOps = ops;\n        }\n    }\n\n    for (auto [d, p] : bestOps) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct SimResult {\n    vector<int> cnt;\n    int end_node;\n    ll err;\n};\n\nstruct BuildResult {\n    vector<int> a, b;\n    ll approx_cost;\n};\n\nstruct Candidate {\n    vector<int> order, a, b, cnt;\n    int end_node = 0;\n    ll err = (1LL << 60);\n    ll approx_cost = (1LL << 60);\n};\n\nint N, Lw;\nvector<int> T;\n\nstatic inline ll absll(ll x) { return x >= 0 ? x : -x; }\n\nbool betterCand(const Candidate& x, const Candidate& y) {\n    if (x.err != y.err) return x.err < y.err;\n    return x.approx_cost < y.approx_cost;\n}\n\nvector<int> normalize_order(vector<int> ord) {\n    int pos = find(ord.begin(), ord.end(), 0) - ord.begin();\n    rotate(ord.begin(), ord.begin() + pos, ord.end());\n    return ord;\n}\n\nvector<int> next_from_order(const vector<int>& order) {\n    vector<int> nxt(N);\n    for (int i = 0; i < N; ++i) nxt[order[i]] = order[(i + 1) % N];\n    return nxt;\n}\n\nvector<int> prev_from_order(const vector<int>& order) {\n    vector<int> prv(N);\n    for (int i = 0; i < N; ++i) prv[order[(i + 1) % N]] = order[i];\n    return prv;\n}\n\nll calc_cost(const vector<int>& assign, const vector<int>& item, const vector<int>& need, vector<int>* load_out = nullptr) {\n    vector<int> load(N, 0);\n    for (int i = 0; i < N; ++i) load[assign[i]] += item[i];\n    ll cost = 0;\n    for (int j = 0; j < N; ++j) cost += absll((ll)load[j] - need[j]);\n    if (load_out) *load_out = load;\n    return cost;\n}\n\n// ---------- fast cycle-order surrogate cost ----------\nll edge_cost_fast(int i, int j, const vector<int>& est) {\n    ll half_from_i = (est[i] + 1) / 2;\n    ll cap_j = T[j] - (j == 0 ? 1 : 0);\n    if (cap_j < 0) cap_j = 0;\n    ll ideal = (cap_j + 1) / 2;\n    ll over = max(0LL, half_from_i - cap_j);\n    ll sim = absll((ll)est[i] - est[j]);\n    return over * 20 + absll(half_from_i - ideal) * 4 + sim;\n}\n\nll order_cost_fast(const vector<int>& ord, const vector<int>& est) {\n    ll c = 0;\n    for (int k = 0; k < N; ++k) {\n        int i = ord[k];\n        int j = ord[(k + 1) % N];\n        c += edge_cost_fast(i, j, est);\n    }\n    return c;\n}\n\nvector<int> mutate_order_random(const vector<int>& ord, mt19937& rng) {\n    vector<int> res = ord;\n    int op = (int)(rng() % 3);\n\n    if (op == 0) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) swap(res[x], res[y]);\n    } else if (op == 1) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) {\n            int v = res[x];\n            res.erase(res.begin() + x);\n            if (y > x) --y;\n            res.insert(res.begin() + y, v);\n        }\n    } else {\n        int l = 1 + (int)(rng() % (N - 1));\n        int r = 1 + (int)(rng() % (N - 1));\n        if (l > r) swap(l, r);\n        if (l == r) r = min(N - 1, l + 1);\n        reverse(res.begin() + l, res.begin() + r + 1);\n    }\n    return res;\n}\n\nvector<int> optimize_order_fast(vector<int> ord, const vector<int>& est, mt19937& rng, int iters, double temp0) {\n    ord = normalize_order(ord);\n    ll cur = order_cost_fast(ord, est);\n    vector<int> best = ord;\n    ll bestc = cur;\n\n    uniform_real_distribution<double> U(0.0, 1.0);\n    double temp = temp0;\n    double temp1 = 1.0;\n    double alpha = pow(temp1 / temp0, 1.0 / max(1, iters));\n\n    for (int iter = 0; iter < iters; ++iter) {\n        vector<int> cand = mutate_order_random(ord, rng);\n        ll nc = order_cost_fast(cand, est);\n        if (nc < cur || U(rng) < exp((double)(cur - nc) / max(1.0, temp))) {\n            ord.swap(cand);\n            cur = nc;\n            if (cur < bestc) {\n                bestc = cur;\n                best = ord;\n            }\n        }\n        temp *= alpha;\n    }\n    return best;\n}\n\n// ---------- assignment builders ----------\nvector<int> init_dp_partition(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N), tgt_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    iota(tgt_ord.begin(), tgt_ord.end(), 0);\n\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] < item[b];\n        return a < b;\n    });\n    sort(tgt_ord.begin(), tgt_ord.end(), [&](int a, int b) {\n        if (need[a] != need[b]) return need[a] < need[b];\n        return a < b;\n    });\n\n    vector<ll> pref(N + 1, 0);\n    for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + item[src_ord[i]];\n\n    const ll INF = (1LL << 60);\n    vector<vector<ll>> dp(N + 1, vector<ll>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int k = 0; k < N; ++k) {\n        for (int i = 0; i <= N; ++i) {\n            if (dp[k][i] >= INF) continue;\n            for (int j = i; j <= N; ++j) {\n                ll segsum = pref[j] - pref[i];\n                ll nd = dp[k][i] + absll(segsum - (ll)need[tgt_ord[k]]);\n                if (nd < dp[k + 1][j]) {\n                    dp[k + 1][j] = nd;\n                    par[k + 1][j] = i;\n                }\n            }\n        }\n    }\n\n    vector<int> assign(N, 0);\n    int cur = N;\n    for (int k = N - 1; k >= 0; --k) {\n        int prv = par[k + 1][cur];\n        if (prv < 0) prv = 0;\n        for (int p = prv; p < cur; ++p) assign[src_ord[p]] = tgt_ord[k];\n        cur = prv;\n    }\n    return assign;\n}\n\nvector<int> init_greedy(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] > item[b];\n        return a < b;\n    });\n\n    vector<int> assign(N, 0), load(N, 0);\n\n    for (int s : src_ord) {\n        ll best_delta = (1LL << 60);\n        int best_t = 0;\n        for (int t = 0; t < N; ++t) {\n            ll before = absll((ll)load[t] - need[t]);\n            ll after = absll((ll)load[t] + item[s] - need[t]);\n            ll delta = after - before;\n            ll deficit = (ll)need[t] - load[t];\n            ll best_deficit = (ll)need[best_t] - load[best_t];\n            if (delta < best_delta ||\n                (delta == best_delta && deficit > best_deficit) ||\n                (delta == best_delta && deficit == best_deficit && t < best_t)) {\n                best_delta = delta;\n                best_t = t;\n            }\n        }\n        assign[s] = best_t;\n        load[best_t] += item[s];\n    }\n    return assign;\n}\n\nll local_search_assign(vector<int>& assign, const vector<int>& item, const vector<int>& need) {\n    vector<int> load;\n    ll total = calc_cost(assign, item, need, &load);\n\n    const int MAX_IT = 80;\n    for (int iter = 0; iter < MAX_IT; ++iter) {\n        vector<ll> base(N);\n        for (int j = 0; j < N; ++j) base[j] = absll((ll)load[j] - need[j]);\n\n        ll best_delta = 0;\n        int best_kind = 0;\n        int bi = -1, bj = -1, bk = -1;\n\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i], w = item[i];\n            if (w == 0) continue;\n            for (int v = 0; v < N; ++v) if (v != u) {\n                ll delta = 0;\n                delta += absll((ll)load[u] - w - need[u]) - base[u];\n                delta += absll((ll)load[v] + w - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 1;\n                    bi = i; bj = v;\n                }\n            }\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i], wi = item[i];\n            for (int k = i + 1; k < N; ++k) {\n                int v = assign[k];\n                if (u == v) continue;\n                int wk = item[k];\n                ll delta = 0;\n                delta += absll((ll)load[u] - wi + wk - need[u]) - base[u];\n                delta += absll((ll)load[v] - wk + wi - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 2;\n                    bi = i; bk = k;\n                }\n            }\n        }\n\n        if (best_kind == 0) break;\n\n        if (best_kind == 1) {\n            int i = bi, v = bj;\n            int u = assign[i], w = item[i];\n            load[u] -= w;\n            load[v] += w;\n            assign[i] = v;\n            total += best_delta;\n        } else {\n            int i = bi, k = bk;\n            int u = assign[i], v = assign[k];\n            int wi = item[i], wk = item[k];\n            load[u] = load[u] - wi + wk;\n            load[v] = load[v] - wk + wi;\n            swap(assign[i], assign[k]);\n            total += best_delta;\n        }\n    }\n    return total;\n}\n\n// ---------- build graph from fixed order ----------\nBuildResult build_graph(const vector<int>& order, const vector<int>& est_cnt, bool exact_end, int end_node) {\n    vector<int> nxt = next_from_order(order);\n    vector<int> prv = prev_from_order(order);\n\n    vector<int> out = est_cnt;\n    if (exact_end && 0 <= end_node && end_node < N) out[end_node]--;\n\n    vector<int> fixed_a(N), item_b(N), need(N);\n    for (int i = 0; i < N; ++i) {\n        if (out[i] < 0) out[i] = 0;\n        fixed_a[i] = (out[i] + 1) / 2;\n        item_b[i] = out[i] / 2;\n    }\n    for (int j = 0; j < N; ++j) {\n        need[j] = T[j] - (j == 0 ? 1 : 0) - fixed_a[prv[j]];\n    }\n\n    vector<int> assign1 = init_dp_partition(item_b, need);\n    ll cost1 = local_search_assign(assign1, item_b, need);\n\n    vector<int> assign2 = init_greedy(item_b, need);\n    ll cost2 = local_search_assign(assign2, item_b, need);\n\n    BuildResult res;\n    res.a = move(nxt);\n    if (cost1 <= cost2) {\n        res.b = move(assign1);\n        res.approx_cost = cost1;\n    } else {\n        res.b = move(assign2);\n        res.approx_cost = cost2;\n    }\n    return res;\n}\n\n// ---------- exact simulation ----------\nSimResult simulate_graph(const vector<int>& a, const vector<int>& b) {\n    vector<int> cnt(N, 0);\n    int cur = 0, end_node = 0;\n    for (int week = 0; week < Lw; ++week) {\n        ++cnt[cur];\n        end_node = cur;\n        if (week + 1 == Lw) break;\n        cur = (cnt[cur] & 1) ? a[cur] : b[cur];\n    }\n    ll err = 0;\n    for (int i = 0; i < N; ++i) err += absll((ll)cnt[i] - T[i]);\n    return {cnt, end_node, err};\n}\n\nCandidate make_candidate(const vector<int>& order, const vector<int>& a, const vector<int>& b, ll approx_cost) {\n    SimResult sr = simulate_graph(a, b);\n    Candidate c;\n    c.order = order;\n    c.a = a;\n    c.b = b;\n    c.cnt = sr.cnt;\n    c.end_node = sr.end_node;\n    c.err = sr.err;\n    c.approx_cost = approx_cost;\n    return c;\n}\n\nCandidate evaluate_order(const vector<int>& order, const vector<int>& init_est, bool exact_end_init, int end_init, int refine_rounds) {\n    BuildResult br = build_graph(order, init_est, exact_end_init, end_init);\n    Candidate cur = make_candidate(order, br.a, br.b, br.approx_cost);\n    Candidate best = cur;\n\n    for (int it = 0; it < refine_rounds; ++it) {\n        BuildResult br2 = build_graph(order, cur.cnt, true, cur.end_node);\n        Candidate nxt = make_candidate(order, br2.a, br2.b, br2.approx_cost);\n        if (betterCand(nxt, cur)) {\n            cur = nxt;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- order generators ----------\nvector<int> sorted_order(bool desc) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return desc ? (T[a] > T[b]) : (T[a] < T[b]);\n        return a < b;\n    });\n    return normalize_order(ord);\n}\n\nvector<int> nearest_neighbor_order(int start, bool half_cost_mode) {\n    vector<int> ord;\n    vector<int> used(N, 0);\n    ord.reserve(N);\n    ord.push_back(start);\n    used[start] = 1;\n    int cur = start;\n\n    for (int step = 1; step < N; ++step) {\n        int best = -1;\n        ll best1 = (1LL << 60), best2 = (1LL << 60);\n        for (int v = 0; v < N; ++v) if (!used[v]) {\n            ll c1, c2;\n            if (!half_cost_mode) {\n                c1 = absll((ll)T[cur] - T[v]);\n                c2 = 0;\n            } else {\n                c1 = max(0, (T[cur] + 1) / 2 - T[v]);\n                c2 = absll((ll)T[cur] - T[v]);\n            }\n            if (best == -1 || c1 < best1 || (c1 == best1 && c2 < best2) || (c1 == best1 && c2 == best2 && v < best)) {\n                best = v;\n                best1 = c1;\n                best2 = c2;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return normalize_order(ord);\n}\n\nvector<int> median_out_order(const vector<int>& base_sorted) {\n    vector<int> ord;\n    ord.reserve(N);\n    int mid = N / 2;\n    ord.push_back(base_sorted[mid]);\n    for (int d = 1; (int)ord.size() < N; ++d) {\n        if (mid - d >= 0) ord.push_back(base_sorted[mid - d]);\n        if ((int)ord.size() >= N) break;\n        if (mid + d < N) ord.push_back(base_sorted[mid + d]);\n    }\n    return normalize_order(ord);\n}\n\nvector<int> alternating_low_high_order() {\n    vector<int> s(N);\n    iota(s.begin(), s.end(), 0);\n    sort(s.begin(), s.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return T[a] < T[b];\n        return a < b;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    int l = 0, r = N - 1;\n    while (l <= r) {\n        ord.push_back(s[l++]);\n        if (l <= r) ord.push_back(s[r--]);\n    }\n    return normalize_order(ord);\n}\n\nvoid add_order_if_new(vector<vector<int>>& orders, set<vector<int>>& seen, vector<int> ord) {\n    ord = normalize_order(ord);\n    if (seen.insert(ord).second) orders.push_back(ord);\n}\n\n// ---------- exact local improvement on order ----------\nCandidate improve_candidate_order(Candidate start, mt19937& rng) {\n    Candidate best = start;\n    Candidate cur = start;\n    set<vector<int>> tried;\n    tried.insert(cur.order);\n\n    {\n        auto jumped = optimize_order_fast(cur.order, cur.cnt, rng, 900, 2500.0);\n        if (!tried.count(jumped)) {\n            tried.insert(jumped);\n            Candidate cand = evaluate_order(jumped, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, cur)) cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n\n    for (int iter = 0; iter < 10; ++iter) {\n        vector<int> chosen;\n        ll best_fast = (1LL << 60);\n\n        for (int t = 0; t < 5; ++t) {\n            auto m = mutate_order_random(cur.order, rng);\n            if (tried.count(m)) continue;\n            ll fc = order_cost_fast(m, cur.cnt);\n            if (fc < best_fast) {\n                best_fast = fc;\n                chosen = move(m);\n            }\n        }\n        if (chosen.empty()) continue;\n        tried.insert(chosen);\n\n        Candidate cand = evaluate_order(chosen, cur.cnt, true, cur.end_node, 1);\n        if (betterCand(cand, cur)) {\n            cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n    return best;\n}\n\n// ---------- end-node refinement ----------\nCandidate refine_endnode_candidate(const Candidate& base) {\n    if (base.order.empty()) return base;\n\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> cand_e;\n    cand_e.push_back(base.end_node);\n    cand_e.push_back(0);\n\n    vector<int> def = ids, ex = ids;\n    sort(def.begin(), def.end(), [&](int a, int b) {\n        ll ra = (ll)T[a] - base.cnt[a];\n        ll rb = (ll)T[b] - base.cnt[b];\n        if (ra != rb) return ra > rb;\n        return a < b;\n    });\n    sort(ex.begin(), ex.end(), [&](int a, int b) {\n        ll ra = (ll)base.cnt[a] - T[a];\n        ll rb = (ll)base.cnt[b] - T[b];\n        if (ra != rb) return ra > rb;\n        return a < b;\n    });\n\n    for (int i = 0; i < 8; ++i) cand_e.push_back(def[i]);\n    for (int i = 0; i < 4; ++i) cand_e.push_back(ex[i]);\n\n    sort(cand_e.begin(), cand_e.end());\n    cand_e.erase(unique(cand_e.begin(), cand_e.end()), cand_e.end());\n\n    Candidate best = base;\n    for (int e : cand_e) {\n        Candidate c = evaluate_order(base.order, base.cnt, true, e, 1);\n        if (betterCand(c, best)) best = c;\n    }\n    return best;\n}\n\n// ---------- local graph repair: b-moves ----------\nstruct MoveCand {\n    ll approx_delta;\n    int type; // 0=bmove, 1=amove, 2=bswap\n    int i, v, k;\n};\n\nCandidate local_search_b_moves(Candidate cur, int rounds = 4, int exactTop = 16) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useB(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useB[i] = dep[i] / 2;\n        }\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            ll ra = (ll)T[a] - cur.cnt[a];\n            ll rb = (ll)T[b] - cur.cnt[b];\n            if (ra != rb) return ra > rb;\n            return a < b;\n        });\n\n        vector<int> tgt;\n        for (int k = 0; k < 10; ++k) tgt.push_back(ids[k]);\n        tgt.push_back(0);\n        sort(tgt.begin(), tgt.end());\n        tgt.erase(unique(tgt.begin(), tgt.end()), tgt.end());\n\n        vector<MoveCand> moves;\n        for (int i = 0; i < N; ++i) {\n            int w = useB[i];\n            if (w == 0) continue;\n            int old = cur.b[i];\n            for (int v : tgt) {\n                if (v == old) continue;\n                ll before = absll((ll)cur.cnt[old] - T[old]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[old] - w - T[old]) + absll((ll)cur.cnt[v] + w - T[v]);\n                moves.push_back({after - before, 0, i, v, -1});\n            }\n        }\n\n        sort(moves.begin(), moves.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& mv : moves) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> nb = cur.b;\n            nb[mv.i] = mv.v;\n            SimResult sr = simulate_graph(cur.a, nb);\n            Candidate cand = cur;\n            cand.b = move(nb);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- local graph repair: b-swaps ----------\nCandidate local_search_b_swaps(Candidate cur, int rounds = 2, int exactTop = 12) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useB(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useB[i] = dep[i] / 2;\n        }\n\n        vector<MoveCand> ops;\n        ops.reserve(N * N / 2);\n\n        for (int i = 0; i < N; ++i) {\n            if (useB[i] == 0) continue;\n            for (int k = i + 1; k < N; ++k) {\n                if (useB[k] == 0) continue;\n                int u = cur.b[i], v = cur.b[k];\n                if (u == v) continue;\n                int wi = useB[i], wk = useB[k];\n\n                ll before = absll((ll)cur.cnt[u] - T[u]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[u] - wi + wk - T[u]) + absll((ll)cur.cnt[v] - wk + wi - T[v]);\n                ops.push_back({after - before, 2, i, -1, k});\n            }\n        }\n\n        sort(ops.begin(), ops.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.k < b.k;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& op : ops) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> nb = cur.b;\n            swap(nb[op.i], nb[op.k]);\n            SimResult sr = simulate_graph(cur.a, nb);\n            Candidate cand = cur;\n            cand.b = move(nb);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n\n    return best;\n}\n\n// ---------- cautious final repair: small a-moves ----------\nCandidate local_search_small_a_moves(Candidate cur, int rounds = 2, int exactTop = 10) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useA(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useA[i] = (dep[i] + 1) / 2;\n        }\n\n        vector<int> deficit_ids(N);\n        iota(deficit_ids.begin(), deficit_ids.end(), 0);\n        sort(deficit_ids.begin(), deficit_ids.end(), [&](int a, int b) {\n            ll ra = (ll)T[a] - cur.cnt[a];\n            ll rb = (ll)T[b] - cur.cnt[b];\n            if (ra != rb) return ra > rb;\n            return a < b;\n        });\n\n        vector<int> small_src(N);\n        iota(small_src.begin(), small_src.end(), 0);\n        sort(small_src.begin(), small_src.end(), [&](int a, int b) {\n            if (useA[a] != useA[b]) return useA[a] < useA[b];\n            return a < b;\n        });\n\n        vector<int> tgt;\n        for (int k = 0; k < 8; ++k) tgt.push_back(deficit_ids[k]);\n        tgt.push_back(0);\n        sort(tgt.begin(), tgt.end());\n        tgt.erase(unique(tgt.begin(), tgt.end()), tgt.end());\n\n        vector<MoveCand> moves;\n        int src_take = 0;\n        for (int i : small_src) {\n            if (i == 0) continue;\n            int w = useA[i];\n            if (w == 0) continue;\n            ++src_take;\n            if (src_take > 24) break;\n            int old = cur.a[i];\n            for (int v : tgt) {\n                if (v == old) continue;\n                ll before = absll((ll)cur.cnt[old] - T[old]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[old] - w - T[old]) + absll((ll)cur.cnt[v] + w - T[v]);\n                moves.push_back({after - before, 1, i, v, -1});\n            }\n        }\n\n        sort(moves.begin(), moves.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& mv : moves) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> na = cur.a;\n            na[mv.i] = mv.v;\n            SimResult sr = simulate_graph(na, cur.b);\n            Candidate cand = cur;\n            cand.a = move(na);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- systematic local order search ----------\nvector<int> relocate_order(const vector<int>& ord, int i, int j) {\n    vector<int> res = ord;\n    int v = res[i];\n    res.erase(res.begin() + i);\n    if (j > i) --j;\n    res.insert(res.begin() + j, v);\n    return res;\n}\n\nCandidate systematic_order_relocate_search(Candidate start, int rounds = 3, int exactTop = 8) {\n    Candidate best = start;\n    Candidate cur = start;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<pair<ll, pair<int,int>>> cand_moves;\n        cand_moves.reserve((N - 1) * (N - 2));\n\n        for (int i = 1; i < N; ++i) {\n            for (int j = 1; j < N; ++j) {\n                if (i == j) continue;\n                vector<int> ord2 = relocate_order(cur.order, i, j);\n                ll fc = order_cost_fast(ord2, cur.cnt);\n                cand_moves.push_back({fc, {i, j}});\n            }\n        }\n\n        sort(cand_moves.begin(), cand_moves.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        Candidate best_local = cur;\n        set<vector<int>> used_orders;\n        used_orders.insert(cur.order);\n\n        int tried = 0;\n        for (auto &ent : cand_moves) {\n            if (tried >= exactTop) break;\n            int i = ent.second.first;\n            int j = ent.second.second;\n            vector<int> ord2 = relocate_order(cur.order, i, j);\n            if (!used_orders.insert(ord2).second) continue;\n            ++tried;\n            Candidate cand = evaluate_order(ord2, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, best_local)) best_local = move(cand);\n        }\n\n        if (betterCand(best_local, cur)) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> Lw;\n    T.resize(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    mt19937 rng(123456789);\n\n    vector<vector<int>> seeds;\n    {\n        vector<int> desc = sorted_order(true);\n        vector<int> asc = sorted_order(false);\n\n        vector<int> orig(N), revorig(N);\n        iota(orig.begin(), orig.end(), 0);\n        revorig = orig;\n        reverse(revorig.begin(), revorig.end());\n\n        int imin = min_element(T.begin(), T.end()) - T.begin();\n        int imax = max_element(T.begin(), T.end()) - T.begin();\n\n        seeds.push_back(desc);\n        seeds.push_back(asc);\n        seeds.push_back(normalize_order(orig));\n        seeds.push_back(normalize_order(revorig));\n        seeds.push_back(nearest_neighbor_order(0, false));\n        seeds.push_back(nearest_neighbor_order(0, true));\n        seeds.push_back(nearest_neighbor_order(imin, false));\n        seeds.push_back(nearest_neighbor_order(imax, false));\n        seeds.push_back(nearest_neighbor_order(imax, true));\n        seeds.push_back(median_out_order(desc));\n        {\n            auto tmp = median_out_order(desc);\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n        seeds.push_back(alternating_low_high_order());\n        {\n            auto tmp = alternating_low_high_order();\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n    }\n\n    vector<vector<int>> orders;\n    set<vector<int>> seen;\n    for (auto s : seeds) add_order_if_new(orders, seen, s);\n    for (auto s : seeds) {\n        auto opt = optimize_order_fast(s, T, rng, 1200, 3000.0);\n        add_order_if_new(orders, seen, opt);\n    }\n    for (int rep = 0; rep < 10; ++rep) {\n        auto tmp = seeds[rng() % seeds.size()];\n        int mv = 3 + (rng() % 4);\n        for (int k = 0; k < mv; ++k) tmp = mutate_order_random(tmp, rng);\n        tmp = optimize_order_fast(tmp, T, rng, 900, 2200.0);\n        add_order_if_new(orders, seen, tmp);\n    }\n\n    vector<pair<ll, int>> rank_idx;\n    for (int i = 0; i < (int)orders.size(); ++i) {\n        rank_idx.push_back({order_cost_fast(orders[i], T), i});\n    }\n    sort(rank_idx.begin(), rank_idx.end());\n\n    int M = min<int>(20, rank_idx.size());\n    vector<Candidate> cand_list;\n    cand_list.reserve(M);\n\n    for (int z = 0; z < M; ++z) {\n        int idx = rank_idx[z].second;\n        cand_list.push_back(evaluate_order(orders[idx], T, false, -1, 2));\n    }\n\n    sort(cand_list.begin(), cand_list.end(), [&](const Candidate& x, const Candidate& y) {\n        return betterCand(x, y);\n    });\n\n    Candidate best = cand_list[0];\n\n    int topK = min<int>(3, cand_list.size());\n    for (int i = 0; i < topK; ++i) {\n        Candidate improved = improve_candidate_order(cand_list[i], rng);\n        if (betterCand(improved, best)) best = improved;\n    }\n\n    {\n        Candidate fin = evaluate_order(best.order, best.cnt, true, best.end_node, 2);\n        if (betterCand(fin, best)) best = fin;\n    }\n\n    // systematic local order search around the best basin\n    {\n        Candidate c = systematic_order_relocate_search(best, 3, 8);\n        if (betterCand(c, best)) best = c;\n    }\n\n    {\n        Candidate c = refine_endnode_candidate(best);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_b_moves(best, 4, 16);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_b_swaps(best, 2, 12);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = evaluate_order(best.order, best.cnt, true, best.end_node, 1);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_small_a_moves(best, 2, 10);\n        if (betterCand(c, best)) best = c;\n    }\n    {\n        Candidate c = local_search_b_moves(best, 2, 10);\n        if (betterCand(c, best)) best = c;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << best.a[i] << ' ' << best.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 800;\nstatic constexpr double INF = 1e100;\n\nint N, M, Q, L, Wv;\nvector<int> G;\n\nint LX[MAXN], RX[MAXN], LY[MAXN], RY[MAXN];\nint SX[MAXN], SY[MAXN];\nint WX[MAXN], WY[MAXN];\nuint64_t MKEY[MAXN];\ndouble estD[MAXN][MAXN];\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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), 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 GroupItem {\n    int size;\n    int id;\n};\n\nstruct QueryPlan {\n    int gid;\n    vector<int> subset;\n};\n\nstruct GroupOrderPack {\n    vector<vector<int>> ranked;\n};\n\nstatic inline long long edgeKey(int u, int v) {\n    if (u > v) swap(u, v);\n    return (static_cast<long long>(u) << 11) | v;\n}\n\nuint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nuint64_t mortonEncode(uint32_t x, uint32_t y) {\n    return (uint64_t)part1by1(x) | ((uint64_t)part1by1(y) << 1);\n}\n\nbool cmpMortonCity(int a, int b) {\n    if (MKEY[a] != MKEY[b]) return MKEY[a] < MKEY[b];\n    return a < b;\n}\nbool cmpXCity(int a, int b) {\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    return a < b;\n}\nbool cmpYCity(int a, int b) {\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\nbool cmpSumCity(int a, int b) {\n    int sa = SX[a] + SY[a];\n    int sb = SX[b] + SY[b];\n    if (sa != sb) return sa < sb;\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\nbool cmpDiffCity(int a, int b) {\n    int da = SX[a] - SY[a];\n    int db = SX[b] - SY[b];\n    if (da != db) return da < db;\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\n\nvector<int> sort_morton(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpMortonCity);\n    return v;\n}\nvector<int> sort_x(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpXCity);\n    return v;\n}\nvector<int> sort_y(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpYCity);\n    return v;\n}\nvector<int> sort_sum(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpSumCity);\n    return v;\n}\nvector<int> sort_diff(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpDiffCity);\n    return v;\n}\n\nvector<int> nn_order(const vector<int>& group, int startCity) {\n    int g = (int)group.size();\n    vector<char> used(N, 0);\n    vector<int> ord;\n    ord.reserve(g);\n    int cur = startCity;\n    used[cur] = 1;\n    ord.push_back(cur);\n\n    for (int step = 1; step < g; step++) {\n        int best = -1;\n        double bestD = INF;\n        for (int v : group) {\n            if (used[v]) continue;\n            double d = estD[cur][v];\n            if (best == -1 || d < bestD - 1e-12 ||\n                (fabs(d - bestD) <= 1e-12 && cmpMortonCity(v, best))) {\n                best = v;\n                bestD = d;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return ord;\n}\n\ndouble mst_cost_slice(const vector<int>& ord, int st, int len) {\n    if (len <= 1) return 0.0;\n    double md[16];\n    bool used[16];\n    for (int i = 0; i < len; i++) {\n        md[i] = INF;\n        used[i] = false;\n    }\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < len; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < len; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = true;\n        total += bv;\n        int u = ord[st + bi];\n        for (int j = 0; j < len; j++) {\n            if (!used[j]) {\n                double w = estD[u][ord[st + j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\ndouble chain_cover_cost(const vector<int>& ord) {\n    int g = (int)ord.size();\n    if (g <= 1) return 0.0;\n    if (g == 2) return estD[ord[0]][ord[1]];\n    if (g <= L) return mst_cost_slice(ord, 0, g);\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = estD[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<double> dp(remain + 1, INF), ndp(remain + 1, INF);\n    dp[0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        fill(ndp.begin(), ndp.end(), INF);\n        for (int p = 0; p <= remain; p++) {\n            if (dp[p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[p] + wcost[p][t];\n                if (cand < ndp[np]) ndp[np] = cand;\n            }\n        }\n        dp.swap(ndp);\n    }\n    return dp[remain];\n}\n\nvector<int> chain_cover_reconstruct_adds(const vector<int>& ord) {\n    int g = (int)ord.size();\n    vector<int> adds;\n    if (g <= 2) return adds;\n    if (g <= L) {\n        adds.push_back(g - 1);\n        return adds;\n    }\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = estD[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<vector<double>> dp(K + 1, vector<double>(remain + 1, INF));\n    vector<vector<int>> parT(K + 1, vector<int>(remain + 1, -1));\n    vector<vector<int>> parP(K + 1, vector<int>(remain + 1, -1));\n    dp[0][0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        for (int p = 0; p <= remain; p++) {\n            if (dp[b][p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[b][p] + wcost[p][t];\n                if (cand < dp[b + 1][np]) {\n                    dp[b + 1][np] = cand;\n                    parT[b + 1][np] = t;\n                    parP[b + 1][np] = p;\n                }\n            }\n        }\n    }\n\n    int p = remain;\n    for (int b = K; b >= 1; b--) {\n        int t = parT[b][p];\n        if (t < 0) break;\n        adds.push_back(t);\n        p = parP[b][p];\n    }\n    reverse(adds.begin(), adds.end());\n    return adds;\n}\n\nvector<vector<int>> gen_dp_cover_windows(const vector<int>& ord) {\n    int g = (int)ord.size();\n    vector<vector<int>> res;\n    if (g <= 1) return res;\n    if (g <= L) {\n        if (g >= 3) res.push_back(ord);\n        return res;\n    }\n    auto adds = chain_cover_reconstruct_adds(ord);\n    int pos = 0;\n    for (int t : adds) {\n        int sz = t + 1;\n        if (sz >= 3) {\n            res.emplace_back(ord.begin() + pos, ord.begin() + pos + sz);\n        }\n        pos += t;\n    }\n    return res;\n}\n\nvector<vector<int>> gen_regular_windows(const vector<int>& ord, int offset) {\n    int g = (int)ord.size();\n    vector<vector<int>> res;\n    if (g <= L) return res;\n    if (offset < 0 || offset >= (L - 1)) return res;\n    for (int s = offset; s + L <= g; s += (L - 1)) {\n        res.emplace_back(ord.begin() + s, ord.begin() + s + L);\n    }\n    return res;\n}\n\ndouble complete_mst_cost(const vector<int>& group) {\n    int g = (int)group.size();\n    if (g <= 1) return 0.0;\n    vector<double> md(g, INF);\n    vector<char> used(g, 0);\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < g; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < g; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = 1;\n        total += bv;\n        int u = group[bi];\n        for (int j = 0; j < g; j++) {\n            if (!used[j]) {\n                double w = estD[u][group[j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\npair<double, vector<pair<int,int>>> complete_mst_edges(const vector<int>& group) {\n    int g = (int)group.size();\n    if (g <= 1) return {0.0, {}};\n    vector<double> md(g, INF);\n    vector<int> par(g, -1);\n    vector<char> used(g, 0);\n    md[0] = 0.0;\n    double total = 0.0;\n    vector<pair<int,int>> edges;\n    edges.reserve(g - 1);\n\n    for (int it = 0; it < g; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < g; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = 1;\n        total += bv;\n        if (par[bi] != -1) {\n            int a = group[bi], b = group[par[bi]];\n            if (a > b) swap(a, b);\n            edges.push_back({a, b});\n        }\n        int u = group[bi];\n        for (int j = 0; j < g; j++) {\n            if (!used[j]) {\n                double w = estD[u][group[j]];\n                if (w < md[j]) {\n                    md[j] = w;\n                    par[j] = bi;\n                }\n            }\n        }\n    }\n    return {total, edges};\n}\n\nvector<int> mst_preorder_order(const vector<int>& group, const vector<pair<int,int>>& mstEdges) {\n    int g = (int)group.size();\n    if (g <= 2) return group;\n\n    vector<int> pos(N, -1);\n    for (int i = 0; i < g; i++) pos[group[i]] = i;\n\n    vector<vector<int>> adj(g);\n    for (auto [a, b] : mstEdges) {\n        int ia = pos[a], ib = pos[b];\n        if (ia >= 0 && ib >= 0) {\n            adj[ia].push_back(ib);\n            adj[ib].push_back(ia);\n        }\n    }\n\n    int root = 0;\n    for (int i = 1; i < g; i++) {\n        if (cmpMortonCity(group[i], group[root])) root = i;\n    }\n\n    for (int i = 0; i < g; i++) {\n        sort(adj[i].begin(), adj[i].end(), [&](int x, int y) {\n            return cmpMortonCity(group[x], group[y]);\n        });\n    }\n\n    vector<int> ord;\n    ord.reserve(g);\n    vector<int> parent(g, -1), it(g, 0), st;\n    st.push_back(root);\n    parent[root] = -2;\n\n    while (!st.empty()) {\n        int u = st.back();\n        if (it[u] == 0) ord.push_back(group[u]);\n        if (it[u] == (int)adj[u].size()) {\n            st.pop_back();\n            continue;\n        }\n        int v = adj[u][it[u]++];\n        if (v == parent[u]) continue;\n        parent[v] = u;\n        st.push_back(v);\n    }\n    return ord;\n}\n\ndouble span_cost_bbox(int dx, int dy, int cnt, int mode) {\n    double base = (mode == 0) ? (double)(dx + dy) : sqrt((double)dx * dx + (double)dy * dy);\n    return base * sqrt((double)cnt);\n}\n\nvoid kd_rec(const vector<int>& pts, const vector<GroupItem>& items,\n            vector<vector<int>>& ans, int mode) {\n    if ((int)items.size() == 1) {\n        ans[items[0].id] = pts;\n        return;\n    }\n\n    int n = (int)pts.size();\n    int m = (int)items.size();\n\n    vector<vector<char>> poss(m + 1, vector<char>(n + 1, 0));\n    poss[0][0] = 1;\n    for (int i = 0; i < m; i++) {\n        int sz = items[i].size;\n        for (int s = 0; s <= n; s++) {\n            if (!poss[i][s]) continue;\n            poss[i + 1][s] = 1;\n            if (s + sz <= n) poss[i + 1][s + sz] = 1;\n        }\n    }\n\n    vector<int> ordx = pts, ordy = pts;\n    sort(ordx.begin(), ordx.end(), cmpXCity);\n    sort(ordy.begin(), ordy.end(), cmpYCity);\n\n    vector<int> pxMinY(n), pxMaxY(n), sxMinY(n), sxMaxY(n);\n    vector<int> pyMinX(n), pyMaxX(n), syMinX(n), syMaxX(n);\n\n    for (int i = 0; i < n; i++) {\n        int v = ordx[i];\n        if (i == 0) pxMinY[i] = pxMaxY[i] = SY[v];\n        else {\n            pxMinY[i] = min(pxMinY[i - 1], SY[v]);\n            pxMaxY[i] = max(pxMaxY[i - 1], SY[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordx[i];\n        if (i == n - 1) sxMinY[i] = sxMaxY[i] = SY[v];\n        else {\n            sxMinY[i] = min(sxMinY[i + 1], SY[v]);\n            sxMaxY[i] = max(sxMaxY[i + 1], SY[v]);\n        }\n    }\n\n    for (int i = 0; i < n; i++) {\n        int v = ordy[i];\n        if (i == 0) pyMinX[i] = pyMaxX[i] = SX[v];\n        else {\n            pyMinX[i] = min(pyMinX[i - 1], SX[v]);\n            pyMaxX[i] = max(pyMaxX[i - 1], SX[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordy[i];\n        if (i == n - 1) syMinX[i] = syMaxX[i] = SX[v];\n        else {\n            syMinX[i] = min(syMinX[i + 1], SX[v]);\n            syMaxX[i] = max(syMaxX[i + 1], SX[v]);\n        }\n    }\n\n    vector<double> pxSX(n + 1, 0), pxSY(n + 1, 0), pxSXX(n + 1, 0), pxSYY(n + 1, 0);\n    vector<double> pySX(n + 1, 0), pySY(n + 1, 0), pySXX(n + 1, 0), pySYY(n + 1, 0);\n    for (int i = 0; i < n; i++) {\n        int vx = ordx[i], vy = ordy[i];\n        pxSX[i + 1] = pxSX[i] + SX[vx];\n        pxSY[i + 1] = pxSY[i] + SY[vx];\n        pxSXX[i + 1] = pxSXX[i] + 1.0 * SX[vx] * SX[vx];\n        pxSYY[i + 1] = pxSYY[i] + 1.0 * SY[vx] * SY[vx];\n\n        pySX[i + 1] = pySX[i] + SX[vy];\n        pySY[i + 1] = pySY[i] + SY[vy];\n        pySXX[i + 1] = pySXX[i] + 1.0 * SX[vy] * SX[vy];\n        pySYY[i + 1] = pySYY[i] + 1.0 * SY[vy] * SY[vy];\n    }\n\n    auto sse_cost = [&](const vector<double>& SXs, const vector<double>& SYs,\n                        const vector<double>& SXXs, const vector<double>& SYYs,\n                        int l, int r) -> double {\n        int cnt = r - l;\n        if (cnt <= 1) return 0.0;\n        double sumx = SXs[r] - SXs[l];\n        double sumy = SYs[r] - SYs[l];\n        double sumxx = SXXs[r] - SXXs[l];\n        double sumyy = SYYs[r] - SYYs[l];\n        return (sumxx - sumx * sumx / cnt) + (sumyy - sumy * sumy / cnt);\n    };\n\n    double bestScore = INF;\n    int bestS = -1;\n    int bestAxis = 0;\n\n    for (int s = 1; s < n; s++) {\n        if (!poss[m][s]) continue;\n\n        double scoreX, scoreY;\n        if (mode <= 1) {\n            int ldx = SX[ordx[s - 1]] - SX[ordx[0]];\n            int ldy = pxMaxY[s - 1] - pxMinY[s - 1];\n            int rdx = SX[ordx[n - 1]] - SX[ordx[s]];\n            int rdy = sxMaxY[s] - sxMinY[s];\n            scoreX = span_cost_bbox(ldx, ldy, s, mode) + span_cost_bbox(rdx, rdy, n - s, mode);\n\n            int ldy2 = SY[ordy[s - 1]] - SY[ordy[0]];\n            int ldx2 = pyMaxX[s - 1] - pyMinX[s - 1];\n            int rdy2 = SY[ordy[n - 1]] - SY[ordy[s]];\n            int rdx2 = syMaxX[s] - syMinX[s];\n            scoreY = span_cost_bbox(ldx2, ldy2, s, mode) + span_cost_bbox(rdx2, rdy2, n - s, mode);\n        } else {\n            scoreX = sse_cost(pxSX, pxSY, pxSXX, pxSYY, 0, s) +\n                     sse_cost(pxSX, pxSY, pxSXX, pxSYY, s, n);\n            scoreY = sse_cost(pySX, pySY, pySXX, pySYY, 0, s) +\n                     sse_cost(pySX, pySY, pySXX, pySYY, s, n);\n        }\n\n        if (scoreX < bestScore - 1e-9 ||\n            (fabs(scoreX - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n            bestScore = scoreX;\n            bestS = s;\n            bestAxis = 0;\n        }\n        if (scoreY < bestScore - 1e-9 ||\n            (fabs(scoreY - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n            bestScore = scoreY;\n            bestS = s;\n            bestAxis = 1;\n        }\n    }\n\n    if (bestS == -1) {\n        bestS = n / 2;\n        bestAxis = 0;\n    }\n\n    vector<GroupItem> leftItems, rightItems;\n    int sum = bestS;\n    for (int i = m - 1; i >= 0; i--) {\n        int sz = items[i].size;\n        if (sum >= sz && poss[i][sum - sz]) {\n            leftItems.push_back(items[i]);\n            sum -= sz;\n        } else {\n            rightItems.push_back(items[i]);\n        }\n    }\n    reverse(leftItems.begin(), leftItems.end());\n    reverse(rightItems.begin(), rightItems.end());\n\n    const vector<int>& ord = (bestAxis == 0 ? ordx : ordy);\n    vector<int> leftPts(ord.begin(), ord.begin() + bestS);\n    vector<int> rightPts(ord.begin() + bestS, ord.end());\n\n    kd_rec(leftPts, leftItems, ans, mode);\n    kd_rec(rightPts, rightItems, ans, mode);\n}\n\nvector<vector<int>> makeKD(int mode, const vector<int>& itemOrder) {\n    vector<vector<int>> ans(M);\n    vector<int> pts(N);\n    iota(pts.begin(), pts.end(), 0);\n    vector<GroupItem> items;\n    items.reserve(M);\n    for (int gid : itemOrder) items.push_back({G[gid], gid});\n    kd_rec(pts, items, ans, mode);\n    return ans;\n}\n\nvector<vector<int>> makeContiguous(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n    vector<vector<int>> groups(M);\n    int pos = 0;\n    for (int gid : groupOrder) {\n        groups[gid] = vector<int>(cityOrder.begin() + pos, cityOrder.begin() + pos + G[gid]);\n        pos += G[gid];\n    }\n    return groups;\n}\n\ndouble eval_grouping(const vector<vector<int>>& groups) {\n    double sc = 0.0;\n    for (int gid = 0; gid < M; gid++) sc += complete_mst_cost(groups[gid]);\n    return sc;\n}\n\nvector<pair<int,int>> ask(const vector<int>& sub) {\n    cout << \"? \" << sub.size();\n    for (int v : sub) cout << ' ' << v;\n    cout << '\\n';\n    cout.flush();\n\n    vector<pair<int,int>> ret;\n    ret.reserve((int)sub.size() - 1);\n    for (int i = 0; i < (int)sub.size() - 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.push_back({a, b});\n    }\n    return ret;\n}\n\nGroupOrderPack make_group_orders(const vector<int>& group, const vector<pair<int,int>>& mstEdges) {\n    GroupOrderPack pack;\n    int g = (int)group.size();\n    if (g <= 2) {\n        pack.ranked.push_back(group);\n        return pack;\n    }\n\n    vector<vector<int>> cand;\n    auto add_ord = [&](const vector<int>& ord) {\n        for (const auto& ex : cand) if (ex == ord) return;\n        cand.push_back(ord);\n    };\n\n    auto mort = sort_morton(group);\n    auto xord = sort_x(group);\n    auto yord = sort_y(group);\n    auto sord = sort_sum(group);\n    auto dord = sort_diff(group);\n    auto treeord = mst_preorder_order(group, mstEdges);\n\n    add_ord(mort);   { auto t = mort; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(xord);   { auto t = xord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(yord);   { auto t = yord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(sord);   { auto t = sord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(dord);   { auto t = dord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(treeord);{ auto t = treeord; reverse(t.begin(), t.end()); add_ord(t); }\n\n    int leftmost = *min_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n    int rightmost = *max_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n\n    {\n        auto nnL = nn_order(group, leftmost);\n        add_ord(nnL);\n        auto rev = nnL; reverse(rev.begin(), rev.end()); add_ord(rev);\n    }\n    if (rightmost != leftmost) {\n        auto nnR = nn_order(group, rightmost);\n        add_ord(nnR);\n        auto rev = nnR; reverse(rev.begin(), rev.end()); add_ord(rev);\n    }\n\n    vector<pair<double,int>> scored;\n    for (int i = 0; i < (int)cand.size(); i++) {\n        scored.push_back({chain_cover_cost(cand[i]), i});\n    }\n    sort(scored.begin(), scored.end());\n\n    for (auto [c, idx] : scored) pack.ranked.push_back(cand[idx]);\n    return pack;\n}\n\ndouble centroid_proxy_cost(int city, int gid,\n                           const vector<long long>& sumX,\n                           const vector<long long>& sumY,\n                           const vector<int>& gsz) {\n    double cx = (double)sumX[gid] / gsz[gid];\n    double cy = (double)sumY[gid] / gsz[gid];\n    double dx = SX[city] - cx;\n    double dy = SY[city] - cy;\n    return dx * dx + dy * dy;\n}\n\nvoid improve_grouping_swaps(vector<vector<int>>& groups,\n                            const vector<int>& cityMort,\n                            const vector<int>& cityX,\n                            const vector<int>& cityY,\n                            const vector<int>& cityS,\n                            const vector<int>& cityD) {\n    vector<int> cityGroup(N), posInGroup(N), gsz(M);\n    vector<long long> sumX(M, 0), sumY(M, 0);\n    vector<double> gcost(M, 0.0);\n\n    int maxG = 0;\n    for (int gid = 0; gid < M; gid++) {\n        gsz[gid] = (int)groups[gid].size();\n        maxG = max(maxG, gsz[gid]);\n        for (int i = 0; i < gsz[gid]; i++) {\n            int v = groups[gid][i];\n            cityGroup[v] = gid;\n            posInGroup[v] = i;\n            sumX[gid] += SX[v];\n            sumY[gid] += SY[v];\n        }\n        gcost[gid] = complete_mst_cost(groups[gid]);\n    }\n\n    vector<pair<double, pair<int,int>>> candPairs;\n    candPairs.reserve(60000);\n    unordered_set<long long> seen;\n    seen.reserve(70000);\n\n    auto add_pair = [&](int u, int v) {\n        if (u == v) return;\n        if (u > v) swap(u, v);\n        long long key = edgeKey(u, v);\n        if (seen.insert(key).second) {\n            candPairs.push_back({estD[u][v], {u, v}});\n        }\n    };\n\n    auto add_by_order = [&](const vector<int>& ord, int rad) {\n        int n = (int)ord.size();\n        for (int i = 0; i < n; i++) {\n            for (int d = 1; d <= rad; d++) {\n                if (i + d >= n) break;\n                add_pair(ord[i], ord[i + d]);\n            }\n        }\n    };\n\n    add_by_order(cityMort, 6);\n    add_by_order(cityX, 4);\n    add_by_order(cityY, 4);\n    add_by_order(cityS, 4);\n    add_by_order(cityD, 4);\n\n    const int GLOBAL_K = 12;\n    for (int u = 0; u < N; u++) {\n        vector<pair<double,int>> tmp;\n        tmp.reserve(N - 1);\n        for (int v = 0; v < N; v++) {\n            if (u == v) continue;\n            tmp.push_back({estD[u][v], v});\n        }\n        int lim = min(GLOBAL_K, (int)tmp.size());\n        if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n        for (int i = 0; i < lim; i++) add_pair(u, tmp[i].second);\n    }\n\n    const int KGROUP = 3;\n    for (int u = 0; u < N; u++) {\n        int gu = cityGroup[u];\n        vector<pair<double,int>> nearGroups;\n        nearGroups.reserve(M - 1);\n        for (int gv = 0; gv < M; gv++) {\n            if (gv == gu) continue;\n            double cx = (double)sumX[gv] / gsz[gv];\n            double cy = (double)sumY[gv] / gsz[gv];\n            double dx = SX[u] - cx;\n            double dy = SY[u] - cy;\n            nearGroups.push_back({dx * dx + dy * dy, gv});\n        }\n        int glim = min(KGROUP, (int)nearGroups.size());\n        if ((int)nearGroups.size() > glim) {\n            nth_element(nearGroups.begin(), nearGroups.begin() + glim, nearGroups.end());\n        }\n        for (int it = 0; it < glim; it++) {\n            int gv = nearGroups[it].second;\n            int best1 = -1, best2 = -1;\n            double bestD1 = INF, bestD2 = INF;\n            for (int v : groups[gv]) {\n                double d1 = estD[u][v];\n                if (d1 < bestD1) {\n                    bestD1 = d1;\n                    best1 = v;\n                }\n                double d2 = centroid_proxy_cost(v, gu, sumX, sumY, gsz)\n                          - centroid_proxy_cost(v, gv, sumX, sumY, gsz);\n                if (d2 < bestD2) {\n                    bestD2 = d2;\n                    best2 = v;\n                }\n            }\n            if (best1 != -1) add_pair(u, best1);\n            if (best2 != -1) add_pair(u, best2);\n        }\n    }\n\n    sort(candPairs.begin(), candPairs.end(),\n         [&](const auto& a, const auto& b) {\n             if (fabs(a.first - b.first) > 1e-12) return a.first < b.first;\n             if (a.second.first != b.second.first) return a.second.first < b.second.first;\n             return a.second.second < b.second.second;\n         });\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n    };\n\n    double budgetMs = 320.0;\n    if (maxG >= 200) budgetMs = 250.0;\n    else if (maxG >= 120) budgetMs = 285.0;\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (auto& cp : candPairs) {\n            if (elapsed_ms() > budgetMs) return;\n\n            int u = cp.second.first;\n            int v = cp.second.second;\n            int gu = cityGroup[u];\n            int gv = cityGroup[v];\n            if (gu == gv) continue;\n\n            int sa = gsz[gu];\n            int sb = gsz[gv];\n\n            double oldP = centroid_proxy_cost(u, gu, sumX, sumY, gsz)\n                        + centroid_proxy_cost(v, gv, sumX, sumY, gsz);\n            double newP = centroid_proxy_cost(v, gu, sumX, sumY, gsz)\n                        + centroid_proxy_cost(u, gv, sumX, sumY, gsz);\n\n            bool small = (sa + sb <= 20 || sa <= 8 || sb <= 8);\n            long long weight = 1LL * sa * sa + 1LL * sb * sb;\n\n            if (!small && newP >= oldP * 0.988) continue;\n            if (weight > 20000 && newP >= oldP * 0.94) continue;\n            if (weight > 80000 && newP >= oldP * 0.84) continue;\n\n            int pu = posInGroup[u];\n            int pv = posInGroup[v];\n\n            vector<int> A2 = groups[gu];\n            vector<int> B2 = groups[gv];\n            A2[pu] = v;\n            B2[pv] = u;\n\n            double newA = complete_mst_cost(A2);\n            double newB = complete_mst_cost(B2);\n\n            if (newA + newB + 1e-9 < gcost[gu] + gcost[gv]) {\n                groups[gu][pu] = v;\n                groups[gv][pv] = u;\n\n                cityGroup[v] = gu;\n                posInGroup[v] = pu;\n                cityGroup[u] = gv;\n                posInGroup[u] = pv;\n\n                sumX[gu] += SX[v] - SX[u];\n                sumY[gu] += SY[v] - SY[u];\n                sumX[gv] += SX[u] - SX[v];\n                sumY[gv] += SY[u] - SY[v];\n\n                gcost[gu] = newA;\n                gcost[gv] = newB;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n}\n\nvoid improve_grouping_pairwise(vector<vector<int>>& groups) {\n    vector<int> cityGroup(N), posInGroup(N), gsz(M);\n    vector<long long> sumX(M, 0), sumY(M, 0);\n    vector<double> gcost(M, 0.0);\n\n    for (int gid = 0; gid < M; gid++) {\n        gsz[gid] = (int)groups[gid].size();\n        for (int i = 0; i < gsz[gid]; i++) {\n            int v = groups[gid][i];\n            cityGroup[v] = gid;\n            posInGroup[v] = i;\n            sumX[gid] += SX[v];\n            sumY[gid] += SY[v];\n        }\n        gcost[gid] = complete_mst_cost(groups[gid]);\n    }\n\n    vector<pair<double, pair<int,int>>> groupPairs;\n    unordered_set<long long> seen;\n    const int NEAR_G = 4;\n\n    for (int ga = 0; ga < M; ga++) {\n        vector<pair<double,int>> tmp;\n        tmp.reserve(M - 1);\n        double cax = (double)sumX[ga] / gsz[ga];\n        double cay = (double)sumY[ga] / gsz[ga];\n        for (int gb = 0; gb < M; gb++) if (gb != ga) {\n            double cbx = (double)sumX[gb] / gsz[gb];\n            double cby = (double)sumY[gb] / gsz[gb];\n            double dx = cax - cbx, dy = cay - cby;\n            tmp.push_back({dx * dx + dy * dy, gb});\n        }\n        int lim = min(NEAR_G, (int)tmp.size());\n        if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n        for (int i = 0; i < lim; i++) {\n            int gb = tmp[i].second;\n            int x = min(ga, gb), y = max(ga, gb);\n            long long key = 1LL * x * M + y;\n            if (seen.insert(key).second) {\n                groupPairs.push_back({tmp[i].first, {x, y}});\n            }\n        }\n    }\n\n    sort(groupPairs.begin(), groupPairs.end());\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n    };\n    double budgetMs = 100.0;\n\n    auto shortlist = [&](int ga, int gb) -> vector<int> {\n        vector<pair<double,int>> byDelta, byOwn;\n        for (int u : groups[ga]) {\n            double oldc = centroid_proxy_cost(u, ga, sumX, sumY, gsz);\n            double newc = centroid_proxy_cost(u, gb, sumX, sumY, gsz);\n            byDelta.push_back({newc - oldc, u});\n            byOwn.push_back({-oldc, u});\n        }\n        sort(byDelta.begin(), byDelta.end());\n        sort(byOwn.begin(), byOwn.end());\n\n        vector<int> res;\n        auto add = [&](int u) {\n            for (int x : res) if (x == u) return;\n            res.push_back(u);\n        };\n        for (int i = 0; i < min(5, (int)byDelta.size()); i++) add(byDelta[i].second);\n        for (int i = 0; i < min(3, (int)byOwn.size()); i++) add(byOwn[i].second);\n        return res;\n    };\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (auto& gp : groupPairs) {\n            if (elapsed_ms() > budgetMs) return;\n\n            int ga = gp.second.first;\n            int gb = gp.second.second;\n            double oldPair = gcost[ga] + gcost[gb];\n\n            auto A = shortlist(ga, gb);\n            auto B = shortlist(gb, ga);\n            if (A.empty() || B.empty()) continue;\n\n            double bestImp = 0.0;\n            int bestu = -1, bestv = -1;\n            double bestA = 0.0, bestB = 0.0;\n\n            for (int u : A) {\n                for (int v : B) {\n                    double oldP = centroid_proxy_cost(u, ga, sumX, sumY, gsz)\n                                + centroid_proxy_cost(v, gb, sumX, sumY, gsz);\n                    double newP = centroid_proxy_cost(v, ga, sumX, sumY, gsz)\n                                + centroid_proxy_cost(u, gb, sumX, sumY, gsz);\n                    if (newP >= oldP * 0.997 && gsz[ga] + gsz[gb] > 20) continue;\n\n                    int pu = posInGroup[u];\n                    int pv = posInGroup[v];\n\n                    vector<int> A2 = groups[ga];\n                    vector<int> B2 = groups[gb];\n                    A2[pu] = v;\n                    B2[pv] = u;\n\n                    double nA = complete_mst_cost(A2);\n                    double nB = complete_mst_cost(B2);\n                    double imp = oldPair - (nA + nB);\n                    if (imp > bestImp + 1e-9) {\n                        bestImp = imp;\n                        bestu = u;\n                        bestv = v;\n                        bestA = nA;\n                        bestB = nB;\n                    }\n                }\n            }\n\n            if (bestImp > 1e-9) {\n                int pu = posInGroup[bestu];\n                int pv = posInGroup[bestv];\n\n                groups[ga][pu] = bestv;\n                groups[gb][pv] = bestu;\n\n                cityGroup[bestv] = ga;\n                posInGroup[bestv] = pu;\n                cityGroup[bestu] = gb;\n                posInGroup[bestu] = pv;\n\n                sumX[ga] += SX[bestv] - SX[bestu];\n                sumY[ga] += SY[bestv] - SY[bestu];\n                sumX[gb] += SX[bestu] - SX[bestv];\n                sumY[gb] += SY[bestu] - SY[bestv];\n\n                gcost[ga] = bestA;\n                gcost[gb] = bestB;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n}\n\n// New refinement: balanced subset exchange on small shortlists of nearby group pairs.\nvoid improve_grouping_subset_exchange(vector<vector<int>>& groups) {\n    vector<int> cityGroup(N), posInGroup(N), gsz(M);\n    vector<long long> sumX(M, 0), sumY(M, 0);\n    vector<double> gcost(M, 0.0);\n\n    for (int gid = 0; gid < M; gid++) {\n        gsz[gid] = (int)groups[gid].size();\n        for (int i = 0; i < gsz[gid]; i++) {\n            int v = groups[gid][i];\n            cityGroup[v] = gid;\n            posInGroup[v] = i;\n            sumX[gid] += SX[v];\n            sumY[gid] += SY[v];\n        }\n        gcost[gid] = complete_mst_cost(groups[gid]);\n    }\n\n    vector<pair<double, pair<int,int>>> groupPairs;\n    unordered_set<long long> seen;\n    const int NEAR_G = 3;\n\n    for (int ga = 0; ga < M; ga++) {\n        vector<pair<double,int>> tmp;\n        tmp.reserve(M - 1);\n        double cax = (double)sumX[ga] / gsz[ga];\n        double cay = (double)sumY[ga] / gsz[ga];\n        for (int gb = 0; gb < M; gb++) if (gb != ga) {\n            double cbx = (double)sumX[gb] / gsz[gb];\n            double cby = (double)sumY[gb] / gsz[gb];\n            double dx = cax - cbx, dy = cay - cby;\n            tmp.push_back({dx * dx + dy * dy, gb});\n        }\n        int lim = min(NEAR_G, (int)tmp.size());\n        if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n        for (int i = 0; i < lim; i++) {\n            int gb = tmp[i].second;\n            int x = min(ga, gb), y = max(ga, gb);\n            long long key = 1LL * x * M + y;\n            if (seen.insert(key).second) {\n                groupPairs.push_back({tmp[i].first, {x, y}});\n            }\n        }\n    }\n\n    sort(groupPairs.begin(), groupPairs.end());\n\n    auto shortlist = [&](int ga, int gb, int lim) -> vector<int> {\n        vector<pair<double,int>> byDelta, byOwn;\n        for (int u : groups[ga]) {\n            double oldc = centroid_proxy_cost(u, ga, sumX, sumY, gsz);\n            double newc = centroid_proxy_cost(u, gb, sumX, sumY, gsz);\n            byDelta.push_back({newc - oldc, u});\n            byOwn.push_back({-oldc, u});\n        }\n        sort(byDelta.begin(), byDelta.end());\n        sort(byOwn.begin(), byOwn.end());\n\n        vector<int> res;\n        auto add = [&](int u) {\n            for (int x : res) if (x == u) return;\n            res.push_back(u);\n        };\n        for (int i = 0; i < min(lim, (int)byDelta.size()); i++) add(byDelta[i].second);\n        for (int i = 0; i < min(2, (int)byOwn.size()) && (int)res.size() < lim; i++) add(byOwn[i].second);\n        return res;\n    };\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n    };\n    double budgetMs = 110.0;\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (auto& gp : groupPairs) {\n            if (elapsed_ms() > budgetMs) return;\n\n            int ga = gp.second.first;\n            int gb = gp.second.second;\n\n            int limA = 3, limB = 3;\n            if (gsz[ga] + gsz[gb] <= 20) limA = limB = 4;\n\n            auto A = shortlist(ga, gb, limA);\n            auto B = shortlist(gb, ga, limB);\n            if (A.empty() || B.empty()) continue;\n\n            int ka = (int)A.size();\n            int kb = (int)B.size();\n            int s = ka + kb;\n            if (s > 10) continue;\n\n            vector<int> U;\n            U.reserve(s);\n            for (int x : A) U.push_back(x);\n            for (int x : B) U.push_back(x);\n\n            vector<int> posA, posB;\n            posA.reserve(ka);\n            posB.reserve(kb);\n            for (int x : A) posA.push_back(posInGroup[x]);\n            for (int x : B) posB.push_back(posInGroup[x]);\n\n            double oldPair = gcost[ga] + gcost[gb];\n            double oldProxy = 0.0;\n            for (int x : A) oldProxy += centroid_proxy_cost(x, ga, sumX, sumY, gsz);\n            for (int x : B) oldProxy += centroid_proxy_cost(x, gb, sumX, sumY, gsz);\n\n            double bestImp = 0.0;\n            vector<int> bestSelA, bestSelB;\n            double bestA = 0.0, bestB = 0.0;\n\n            int origMask = (1 << ka) - 1;\n\n            for (int mask = 0; mask < (1 << s); mask++) {\n                if (__builtin_popcount((unsigned)mask) != ka) continue;\n                if (mask == origMask) continue;\n\n                vector<int> selA, selB;\n                selA.reserve(ka);\n                selB.reserve(kb);\n\n                double newProxy = 0.0;\n                for (int i = 0; i < s; i++) {\n                    if (mask & (1 << i)) {\n                        selA.push_back(U[i]);\n                        newProxy += centroid_proxy_cost(U[i], ga, sumX, sumY, gsz);\n                    } else {\n                        selB.push_back(U[i]);\n                        newProxy += centroid_proxy_cost(U[i], gb, sumX, sumY, gsz);\n                    }\n                }\n\n                if (newProxy >= oldProxy * 0.997 && gsz[ga] + gsz[gb] > 24) continue;\n\n                vector<int> A2 = groups[ga];\n                vector<int> B2 = groups[gb];\n                for (int i = 0; i < ka; i++) A2[posA[i]] = selA[i];\n                for (int i = 0; i < kb; i++) B2[posB[i]] = selB[i];\n\n                double nA = complete_mst_cost(A2);\n                double nB = complete_mst_cost(B2);\n                double imp = oldPair - (nA + nB);\n                if (imp > bestImp + 1e-9) {\n                    bestImp = imp;\n                    bestSelA = selA;\n                    bestSelB = selB;\n                    bestA = nA;\n                    bestB = nB;\n                }\n            }\n\n            if (bestImp > 1e-9) {\n                vector<int> oldA = A, oldB = B;\n\n                for (int i = 0; i < ka; i++) {\n                    groups[ga][posA[i]] = bestSelA[i];\n                    cityGroup[bestSelA[i]] = ga;\n                    posInGroup[bestSelA[i]] = posA[i];\n                }\n                for (int i = 0; i < kb; i++) {\n                    groups[gb][posB[i]] = bestSelB[i];\n                    cityGroup[bestSelB[i]] = gb;\n                    posInGroup[bestSelB[i]] = posB[i];\n                }\n\n                long long oldSumAX = 0, oldSumAY = 0, newSumAX = 0, newSumAY = 0;\n                long long oldSumBX = 0, oldSumBY = 0, newSumBX = 0, newSumBY = 0;\n                for (int x : oldA) { oldSumAX += SX[x]; oldSumAY += SY[x]; }\n                for (int x : oldB) { oldSumBX += SX[x]; oldSumBY += SY[x]; }\n                for (int x : bestSelA) { newSumAX += SX[x]; newSumAY += SY[x]; }\n                for (int x : bestSelB) { newSumBX += SX[x]; newSumBY += SY[x]; }\n\n                sumX[ga] += newSumAX - oldSumAX;\n                sumY[ga] += newSumAY - oldSumAY;\n                sumX[gb] += newSumBX - oldSumBX;\n                sumY[gb] += newSumBY - oldSumBY;\n\n                gcost[ga] = bestA;\n                gcost[gb] = bestB;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> Q >> L >> Wv;\n    G.resize(M);\n    for (int i = 0; i < M; i++) cin >> G[i];\n\n    for (int i = 0; i < N; i++) {\n        cin >> LX[i] >> RX[i] >> LY[i] >> RY[i];\n        SX[i] = LX[i] + RX[i];\n        SY[i] = LY[i] + RY[i];\n        WX[i] = RX[i] - LX[i];\n        WY[i] = RY[i] - LY[i];\n        MKEY[i] = mortonEncode((uint32_t)SX[i], (uint32_t)SY[i]);\n    }\n\n    vector<double> varTerm(N);\n    for (int i = 0; i < N; i++) {\n        varTerm[i] = (1.0 * WX[i] * WX[i] + 1.0 * WY[i] * WY[i]) / 12.0;\n    }\n    for (int i = 0; i < N; i++) {\n        estD[i][i] = 0.0;\n        for (int j = i + 1; j < N; j++) {\n            double dx = (SX[i] - SX[j]) * 0.5;\n            double dy = (SY[i] - SY[j]) * 0.5;\n            double d2 = dx * dx + dy * dy + varTerm[i] + varTerm[j];\n            estD[i][j] = estD[j][i] = sqrt(max(0.0, d2));\n        }\n    }\n\n    vector<int> allCities(N);\n    iota(allCities.begin(), allCities.end(), 0);\n\n    vector<int> cityMort = allCities, cityX = allCities, cityY = allCities, cityS = allCities, cityD = allCities;\n    sort(cityMort.begin(), cityMort.end(), cmpMortonCity);\n    sort(cityX.begin(), cityX.end(), cmpXCity);\n    sort(cityY.begin(), cityY.end(), cmpYCity);\n    sort(cityS.begin(), cityS.end(), cmpSumCity);\n    sort(cityD.begin(), cityD.end(), cmpDiffCity);\n\n    vector<int> cityMortRev = cityMort, cityXRev = cityX, cityYRev = cityY, citySRev = cityS, cityDRev = cityD;\n    reverse(cityMortRev.begin(), cityMortRev.end());\n    reverse(cityXRev.begin(), cityXRev.end());\n    reverse(cityYRev.begin(), cityYRev.end());\n    reverse(citySRev.begin(), citySRev.end());\n    reverse(cityDRev.begin(), cityDRev.end());\n\n    vector<int> groupAsc(M), groupDesc(M), groupOrig(M), groupRnd(M);\n    iota(groupAsc.begin(), groupAsc.end(), 0);\n    iota(groupDesc.begin(), groupDesc.end(), 0);\n    iota(groupOrig.begin(), groupOrig.end(), 0);\n    iota(groupRnd.begin(), groupRnd.end(), 0);\n\n    sort(groupAsc.begin(), groupAsc.end(), [&](int a, int b) {\n        if (G[a] != G[b]) return G[a] < G[b];\n        return a < b;\n    });\n    groupDesc = groupAsc;\n    reverse(groupDesc.begin(), groupDesc.end());\n\n    mt19937 rng(123456789);\n    shuffle(groupRnd.begin(), groupRnd.end(), rng);\n\n    double bestGroupingScore = INF;\n    vector<vector<int>> bestGroups;\n\n    auto try_grouping = [&](vector<vector<int>> cand) {\n        double sc = eval_grouping(cand);\n        if (sc < bestGroupingScore) {\n            bestGroupingScore = sc;\n            bestGroups = move(cand);\n        }\n    };\n\n    for (int mode = 0; mode < 3; mode++) {\n        try_grouping(makeKD(mode, groupAsc));\n        try_grouping(makeKD(mode, groupDesc));\n        try_grouping(makeKD(mode, groupOrig));\n        try_grouping(makeKD(mode, groupRnd));\n    }\n\n    try_grouping(makeContiguous(cityMort, groupAsc));\n    try_grouping(makeContiguous(cityMort, groupDesc));\n    try_grouping(makeContiguous(cityMort, groupOrig));\n    try_grouping(makeContiguous(cityMortRev, groupAsc));\n    try_grouping(makeContiguous(cityMortRev, groupDesc));\n\n    try_grouping(makeContiguous(cityX, groupAsc));\n    try_grouping(makeContiguous(cityX, groupDesc));\n    try_grouping(makeContiguous(cityX, groupOrig));\n    try_grouping(makeContiguous(cityXRev, groupAsc));\n    try_grouping(makeContiguous(cityXRev, groupDesc));\n\n    try_grouping(makeContiguous(cityY, groupAsc));\n    try_grouping(makeContiguous(cityY, groupDesc));\n    try_grouping(makeContiguous(cityY, groupOrig));\n    try_grouping(makeContiguous(cityYRev, groupAsc));\n    try_grouping(makeContiguous(cityYRev, groupDesc));\n\n    try_grouping(makeContiguous(cityS, groupAsc));\n    try_grouping(makeContiguous(cityS, groupDesc));\n    try_grouping(makeContiguous(cityS, groupOrig));\n    try_grouping(makeContiguous(citySRev, groupAsc));\n    try_grouping(makeContiguous(citySRev, groupDesc));\n\n    try_grouping(makeContiguous(cityD, groupAsc));\n    try_grouping(makeContiguous(cityD, groupDesc));\n    try_grouping(makeContiguous(cityD, groupOrig));\n    try_grouping(makeContiguous(cityDRev, groupAsc));\n    try_grouping(makeContiguous(cityDRev, groupDesc));\n\n    improve_grouping_swaps(bestGroups, cityMort, cityX, cityY, cityS, cityD);\n    improve_grouping_pairwise(bestGroups);\n    improve_grouping_subset_exchange(bestGroups);\n\n    vector<GroupOrderPack> orderPacks(M);\n    vector<double> groupEstCost(M, 0.0);\n    vector<vector<pair<int,int>>> estMSTEdges(M);\n    vector<vector<int>> outputCityOrder(M);\n    vector<int> baseNeed(M, 0);\n\n    for (int gid = 0; gid < M; gid++) {\n        groupEstCost[gid] = complete_mst_cost(bestGroups[gid]);\n        auto mstInfo = complete_mst_edges(bestGroups[gid]);\n        estMSTEdges[gid] = mstInfo.second;\n\n        orderPacks[gid] = make_group_orders(bestGroups[gid], estMSTEdges[gid]);\n        if (!orderPacks[gid].ranked.empty()) outputCityOrder[gid] = orderPacks[gid].ranked[0];\n        else outputCityOrder[gid] = bestGroups[gid];\n\n        baseNeed[gid] = (int)gen_dp_cover_windows(outputCityOrder[gid]).size();\n        if (G[gid] == 2) baseNeed[gid] = 0;\n        if (3 <= G[gid] && G[gid] <= L) baseNeed[gid] = 1;\n    }\n\n    vector<int> priorityGroups(M);\n    iota(priorityGroups.begin(), priorityGroups.end(), 0);\n    sort(priorityGroups.begin(), priorityGroups.end(), [&](int a, int b) {\n        double va = groupEstCost[a] / max(1, baseNeed[a]);\n        double vb = groupEstCost[b] / max(1, baseNeed[b]);\n        if (fabs(va - vb) > 1e-12) return va > vb;\n        if (fabs(groupEstCost[a] - groupEstCost[b]) > 1e-12) return groupEstCost[a] > groupEstCost[b];\n        return G[a] > G[b];\n    });\n\n    vector<set<vector<int>>> seenSubsets(M);\n    vector<QueryPlan> plans;\n    plans.reserve(Q);\n\n    auto try_add_plan = [&](int gid, const vector<int>& sub) {\n        if ((int)plans.size() >= Q) return;\n        if ((int)sub.size() < 3 || (int)sub.size() > L) return;\n        vector<int> key = sub;\n        sort(key.begin(), key.end());\n        if (seenSubsets[gid].insert(key).second) {\n            plans.push_back({gid, sub});\n        }\n    };\n\n    for (int gid = 0; gid < M; gid++) {\n        int g = G[gid];\n        if (g < 3) continue;\n        if (g <= L) {\n            try_add_plan(gid, outputCityOrder[gid]);\n        } else {\n            auto wins = gen_dp_cover_windows(outputCityOrder[gid]);\n            for (auto& sub : wins) try_add_plan(gid, sub);\n        }\n    }\n\n    int midOffset = (L - 1) / 2;\n\n    auto add_round = [&](int ordIdx, int offset, bool coverStyle) {\n        vector<vector<vector<int>>> wins(M);\n        int mx = 0;\n        for (int gid : priorityGroups) {\n            if ((int)plans.size() >= Q) return;\n            if (G[gid] <= L) continue;\n            if ((int)orderPacks[gid].ranked.size() <= ordIdx) continue;\n            const auto& ord = orderPacks[gid].ranked[ordIdx];\n            if (coverStyle) wins[gid] = gen_dp_cover_windows(ord);\n            else wins[gid] = gen_regular_windows(ord, offset);\n            mx = max(mx, (int)wins[gid].size());\n        }\n        for (int t = 0; t < mx; t++) {\n            for (int gid : priorityGroups) {\n                if ((int)plans.size() >= Q) return;\n                if (t < (int)wins[gid].size()) try_add_plan(gid, wins[gid][t]);\n            }\n        }\n    };\n\n    add_round(1, 0, true);\n    if (midOffset > 0) add_round(0, midOffset, false);\n    if (midOffset > 0) add_round(1, midOffset, false);\n    add_round(2, 0, true);\n    if (midOffset != 1 && L >= 4) add_round(0, 1, false);\n\n    vector<unordered_map<long long,int>> queryEdgeCount(M);\n    vector<vector<pair<int,int>>> exactSmallGroupEdges(M);\n\n    for (auto& qp : plans) {\n        auto ret = ask(qp.subset);\n        for (auto [a, b] : ret) {\n            queryEdgeCount[qp.gid][edgeKey(a, b)]++;\n        }\n        if (G[qp.gid] >= 3 && G[qp.gid] <= L) {\n            if ((int)qp.subset.size() == G[qp.gid]) {\n                exactSmallGroupEdges[qp.gid] = ret;\n            }\n        }\n    }\n\n    vector<vector<pair<int,int>>> answerEdges(M);\n\n    for (int gid = 0; gid < M; gid++) {\n        int g = G[gid];\n        const auto& group = bestGroups[gid];\n        answerEdges[gid].clear();\n\n        if (g <= 1) continue;\n\n        if (g == 2) {\n            int a = group[0], b = group[1];\n            if (a > b) swap(a, b);\n            answerEdges[gid].push_back({a, b});\n            continue;\n        }\n\n        if (g <= L && !exactSmallGroupEdges[gid].empty()) {\n            answerEdges[gid] = exactSmallGroupEdges[gid];\n            sort(answerEdges[gid].begin(), answerEdges[gid].end());\n            continue;\n        }\n\n        unordered_map<long long,int> qcnt = queryEdgeCount[gid];\n        unordered_set<long long> edgeSeen;\n\n        struct EItem {\n            double w;\n            int u, v;\n        };\n        vector<EItem> cand;\n        cand.reserve(g * 36);\n\n        auto addCand = [&](int u, int v) {\n            if (u == v) return;\n            if (u > v) swap(u, v);\n            long long key = edgeKey(u, v);\n            if (!edgeSeen.insert(key).second) return;\n            int cnt = 0;\n            auto it = qcnt.find(key);\n            if (it != qcnt.end()) cnt = it->second;\n            double factor = 1.0 / (1.0 + 0.18 * min(cnt, 4));\n            cand.push_back({estD[u][v] * factor, u, v});\n        };\n\n        for (auto& kv : qcnt) {\n            int u = (int)(kv.first >> 11);\n            int v = (int)(kv.first & ((1 << 11) - 1));\n            addCand(u, v);\n        }\n\n        for (auto [a, b] : estMSTEdges[gid]) addCand(a, b);\n\n        vector<vector<int>> useOrders;\n        for (int t = 0; t < min(6, (int)orderPacks[gid].ranked.size()); t++) {\n            useOrders.push_back(orderPacks[gid].ranked[t]);\n        }\n        auto ensure_order = [&](const vector<int>& ord) {\n            for (auto& v : useOrders) if (v == ord) return;\n            useOrders.push_back(ord);\n        };\n        ensure_order(sort_morton(group));\n        ensure_order(sort_x(group));\n        ensure_order(sort_y(group));\n        ensure_order(sort_sum(group));\n        ensure_order(sort_diff(group));\n\n        for (int oi = 0; oi < (int)useOrders.size(); oi++) {\n            auto& ord = useOrders[oi];\n            int gg = (int)ord.size();\n            int maxJump = (oi < 4 ? 3 : 2);\n            for (int i = 0; i < gg; i++) {\n                for (int d = 1; d <= maxJump; d++) {\n                    if (i + d < gg) addCand(ord[i], ord[i + d]);\n                }\n            }\n        }\n\n        const int KNN = 6;\n        for (int i = 0; i < g; i++) {\n            int u = group[i];\n            vector<pair<double,int>> tmp;\n            tmp.reserve(g - 1);\n            for (int j = 0; j < g; j++) {\n                if (i == j) continue;\n                int v = group[j];\n                tmp.push_back({estD[u][v], v});\n            }\n            int lim = min(KNN, (int)tmp.size());\n            if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n            for (int t = 0; t < lim; t++) addCand(u, tmp[t].second);\n        }\n\n        sort(cand.begin(), cand.end(), [&](const EItem& a, const EItem& b) {\n            if (fabs(a.w - b.w) > 1e-12) return a.w < b.w;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        DSU dsu(N);\n        vector<pair<int,int>> chosen;\n        chosen.reserve(g - 1);\n\n        for (auto& e : cand) {\n            if (dsu.unite(e.u, e.v)) {\n                chosen.push_back({e.u, e.v});\n                if ((int)chosen.size() == g - 1) break;\n            }\n        }\n\n        if ((int)chosen.size() < g - 1) {\n            auto ord = outputCityOrder[gid];\n            for (int i = 1; i < (int)ord.size(); i++) {\n                int a = ord[i - 1], b = ord[i];\n                if (a > b) swap(a, b);\n                if (dsu.unite(a, b)) chosen.push_back({a, b});\n            }\n        }\n\n        for (auto& e : chosen) {\n            if (e.first > e.second) swap(e.first, e.second);\n        }\n        sort(chosen.begin(), chosen.end());\n        answerEdges[gid] = move(chosen);\n    }\n\n    cout << \"!\" << '\\n';\n    for (int gid = 0; gid < M; gid++) {\n        const auto& ord = outputCityOrder[gid];\n        for (int i = 0; i < (int)ord.size(); i++) {\n            if (i) cout << ' ';\n            cout << ord[i];\n        }\n        cout << '\\n';\n        for (auto [a, b] : answerEdges[gid]) {\n            cout << a << ' ' << b << '\\n';\n        }\n    }\n    cout.flush();\n\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 40;\nstatic constexpr int MAXV = 400;\nstatic constexpr int INF = 1e9;\n\nstruct Point {\n    int r, c;\n};\n\nstruct Cmd {\n    char a, d;\n};\n\nstruct Graph {\n    array<uint8_t, MAXV> cnt{};\n    array<array<uint16_t, 8>, MAXV> to{};\n    array<array<uint8_t, 8>, MAXV> act{};\n\n    array<uint8_t, MAXV> rcnt{};\n    array<array<uint16_t, 128>, MAXV> rev{};\n};\n\nstruct Solver {\n    int N, M, V;\n    array<Point, MAXM> pts{};\n    array<int, MAXM> cells{};\n    array<int, MAXV> rankCell{}; // -1 if not target, else target index\n\n    vector<int> cand[MAXM]; // candidate stopper cell ids for each target, includes -1\n\n    mt19937 rng{123456789};\n    chrono::steady_clock::time_point st;\n    double TL = 1.78;\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n    const char dirC[4] = {'U', 'D', 'L', 'R'};\n\n    Graph g0, g1;\n    array<short, MAXV> dist0{}, dist1{}, dist2{};\n    array<short, MAXV> prevPos{};\n    array<int8_t, MAXV> prevAct{};\n\n    using Assign = array<int, MAXM>;\n\n    Solver(int N_, int M_, const vector<Point>& in) : N(N_), M(M_), V(N_ * N_) {\n        rankCell.fill(-1);\n        for (int i = 0; i < M; i++) {\n            pts[i] = in[i];\n            cells[i] = id(pts[i].r, pts[i].c);\n            rankCell[cells[i]] = i;\n        }\n        build_candidates();\n        st = chrono::steady_clock::now();\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    inline bool time_up(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline int id(int r, int c) const { return r * N + c; }\n    inline int row(int v) const { return v / N; }\n    inline int col(int v) const { return v % N; }\n    inline bool inside(int r, int c) const { return 0 <= r && r < N && 0 <= c && c < N; }\n\n    int adj_dir(int from, int to) const {\n        int fr = row(from), fc = col(from);\n        int tr = row(to), tc = col(to);\n        for (int d = 0; d < 4; d++) {\n            if (fr + dr[d] == tr && fc + dc[d] == tc) return d;\n        }\n        return -1;\n    }\n\n    void build_candidates() {\n        for (int k = 1; k < M; k++) {\n            cand[k].clear();\n            cand[k].push_back(-1);\n\n            int r = pts[k].r, c = pts[k].c;\n            vector<int> tmp;\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                int v = id(nr, nc);\n                // Allow non-target or already visited target as blocker cell.\n                if (rankCell[v] == -1 || rankCell[v] < k) tmp.push_back(v);\n            }\n            sort(tmp.begin(), tmp.end());\n            tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());\n            for (int v : tmp) cand[k].push_back(v);\n        }\n    }\n\n    void build_graph(const array<uint8_t, MAXV>& blocked, Graph& g) const {\n        int slU[MAXV], slD[MAXV], slL[MAXV], slR[MAXV];\n        g.cnt.fill(0);\n        g.rcnt.fill(0);\n\n        for (int r = 0; r < N; r++) {\n            int lb = -1;\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                if (blocked[v]) lb = c;\n                else slL[v] = id(r, lb + 1);\n            }\n            int rb = N;\n            for (int c = N - 1; c >= 0; c--) {\n                int v = id(r, c);\n                if (blocked[v]) rb = c;\n                else slR[v] = id(r, rb - 1);\n            }\n        }\n\n        for (int c = 0; c < N; c++) {\n            int ub = -1;\n            for (int r = 0; r < N; r++) {\n                int v = id(r, c);\n                if (blocked[v]) ub = r;\n                else slU[v] = id(ub + 1, c);\n            }\n            int db = N;\n            for (int r = N - 1; r >= 0; r--) {\n                int v = id(r, c);\n                if (blocked[v]) db = r;\n                else slD[v] = id(db - 1, c);\n            }\n        }\n\n        for (int p = 0; p < V; p++) {\n            if (blocked[p]) continue;\n            int r = row(p), c = col(p);\n\n            auto add_edge = [&](int to, int act) {\n                if (to == p) return;\n                auto &cc = g.cnt[p];\n                for (int i = 0; i < cc; i++) {\n                    if (g.to[p][i] == to) return;\n                }\n                g.to[p][cc] = (uint16_t)to;\n                g.act[p][cc] = (uint8_t)act;\n                cc++;\n            };\n\n            add_edge(slU[p], 4);\n            add_edge(slD[p], 5);\n            add_edge(slL[p], 6);\n            add_edge(slR[p], 7);\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                int v = id(nr, nc);\n                if (!blocked[v]) add_edge(v, d);\n            }\n        }\n\n        for (int u = 0; u < V; u++) {\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                g.rev[v][g.rcnt[v]++] = (uint16_t)u;\n            }\n        }\n    }\n\n    void bfs_all(const Graph& g, int src, int forbid, array<short, MAXV>& dist) const {\n        dist.fill(-1);\n        if (src == forbid) return;\n\n        static int q[MAXV];\n        int qh = 0, qt = 0;\n        dist[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    void bfs_rev_all(const Graph& g, int dst, int forbid, array<short, MAXV>& dist) const {\n        dist.fill(-1);\n        if (dst == forbid) return;\n\n        static int q[MAXV];\n        int qh = 0, qt = 0;\n        dist[dst] = 0;\n        q[qt++] = dst;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.rcnt[u]; i++) {\n                int v = g.rev[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    bool bfs_path(const Graph& g, int src, int dst, int forbid, vector<int>& acts) {\n        acts.clear();\n        if (src == dst) return true;\n\n        dist0.fill(-1);\n        prevPos.fill(-1);\n        prevAct.fill(-1);\n\n        if (src == forbid) return false;\n\n        static int q[MAXV];\n        int qh = 0, qt = 0;\n        dist0[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist0[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist0[v] != -1) continue;\n                dist0[v] = nd;\n                prevPos[v] = (short)u;\n                prevAct[v] = (int8_t)g.act[u][i];\n                if (v == dst) {\n                    qh = qt;\n                    break;\n                }\n                q[qt++] = v;\n            }\n        }\n\n        if (dist0[dst] == -1) return false;\n\n        int cur = dst;\n        while (cur != src) {\n            acts.push_back(prevAct[cur]);\n            cur = prevPos[cur];\n        }\n        reverse(acts.begin(), acts.end());\n        return true;\n    }\n\n    void append_acts(vector<Cmd>& ans, const vector<int>& acts) const {\n        for (int a : acts) {\n            if (a < 4) ans.push_back({'M', dirC[a]});\n            else ans.push_back({'S', dirC[a - 4]});\n        }\n    }\n\n    Cmd alter_cmd(int from, int block_cell) const {\n        int d = adj_dir(from, block_cell);\n        return {'A', dirC[d]};\n    }\n\n    // Exact evaluation with lazy placement.\n    int eval_assignment(const Assign& asg, int cutoff = INF) {\n        array<uint8_t, MAXV> blocked{}, used{};\n        blocked.fill(0);\n        used.fill(0);\n\n        int total = 0;\n        for (int k = 1; k < M; k++) {\n            int x = asg[k];\n            if (x != -1 && !used[x]) {\n                used[x] = 1;\n                total++;\n            }\n        }\n        if (total >= cutoff) return total;\n\n        bool haveG = false;\n        int cur = cells[0];\n\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            if (!haveG) {\n                build_graph(blocked, g0);\n                haveG = true;\n            }\n\n            bfs_all(g0, cur, -1, dist0);\n            int best = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            bool add_new = (x != -1 && !blocked[x]);\n            if (add_new) {\n                bfs_all(g0, cur, target, dist1);\n\n                blocked[x] = 1;\n                build_graph(blocked, g1);\n                bfs_rev_all(g1, target, -1, dist2);\n                blocked[x] = 0;\n\n                int xr = row(x), xc = col(x);\n                int pre = INF;\n                for (int d = 0; d < 4; d++) {\n                    int vr = xr + dr[d], vc = xc + dc[d];\n                    if (!inside(vr, vc)) continue;\n                    int v = id(vr, vc);\n                    if (v == target) continue;\n                    if (blocked[v]) continue;\n                    if (dist1[v] == -1 || dist2[v] == -1) continue;\n                    pre = min(pre, (int)dist1[v] + (int)dist2[v]);\n                }\n                best = min(best, pre);\n            }\n\n            if (best >= INF) return INF;\n            total += best;\n            if (total >= cutoff) return total;\n\n            if (add_new) {\n                blocked[x] = 1;\n                g0 = g1;      // reuse next graph\n                haveG = true;\n            }\n            cur = target;\n        }\n        return total;\n    }\n\n    Assign none_assign() const {\n        Assign a;\n        a.fill(-1);\n        return a;\n    }\n\n    Assign heuristic_prev_assign() const {\n        Assign asg;\n        asg.fill(-1);\n\n        for (int k = 1; k < M; k++) {\n            int cur = cells[k], prv = cells[k - 1];\n            int r = row(cur), c = col(cur);\n            int pr = row(prv), pc = col(prv);\n\n            vector<int> pref;\n            if (abs(pc - c) <= abs(pr - r)) {\n                if (pr <= r) pref = {1, 0, 3, 2};\n                else         pref = {0, 1, 2, 3};\n            } else {\n                if (pc <= c) pref = {3, 2, 1, 0};\n                else         pref = {2, 3, 0, 1};\n            }\n\n            int chosen = -1;\n            for (int pd : pref) {\n                for (int x : cand[k]) {\n                    if (x == -1) continue;\n                    if (adj_dir(cur, x) == pd) {\n                        chosen = x;\n                        break;\n                    }\n                }\n                if (chosen != -1) break;\n            }\n            asg[k] = chosen;\n        }\n        return asg;\n    }\n\n    // Greedy completion from a fixed prefix [1, start_k-1].\n    // If lookahead=true, prefer choices that also help the next segment.\n    Assign greedy_from_prefix(const Assign& base, int start_k, bool lookahead) {\n        Assign asg = base;\n\n        array<uint8_t, MAXV> used{}, blocked{};\n        used.fill(0);\n        blocked.fill(0);\n\n        for (int k = 1; k < start_k; k++) {\n            int x = asg[k];\n            if (x != -1) {\n                used[x] = 1;\n                blocked[x] = 1;\n            }\n        }\n\n        int cur = cells[start_k - 1];\n        bool haveG = false;\n\n        for (int k = start_k; k < M; k++) {\n            int target = cells[k];\n            int nxt = (k + 1 < M ? cells[k + 1] : -1);\n\n            if (!haveG) {\n                build_graph(blocked, g0);\n                haveG = true;\n            }\n\n            bfs_all(g0, cur, -1, dist0);\n            int direct = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            bool anyNew = false;\n            for (int x : cand[k]) {\n                if (x != -1 && !blocked[x]) {\n                    anyNew = true;\n                    break;\n                }\n            }\n            if (anyNew) bfs_all(g0, cur, target, dist1);\n\n            int bestx = -1;\n            int bestHeu = INF;\n            int bestBase = INF;\n\n            for (int x : cand[k]) {\n                int mv = direct;\n                int nextDist = 0;\n                bool add_new = (x != -1 && !blocked[x]);\n                const Graph* afterG = &g0;\n\n                if (add_new) {\n                    blocked[x] = 1;\n                    build_graph(blocked, g1);\n                    blocked[x] = 0;\n                    afterG = &g1;\n\n                    bfs_rev_all(g1, target, -1, dist2);\n                    int xr = row(x), xc = col(x);\n                    int pre = INF;\n                    for (int d = 0; d < 4; d++) {\n                        int vr = xr + dr[d], vc = xc + dc[d];\n                        if (!inside(vr, vc)) continue;\n                        int v = id(vr, vc);\n                        if (v == target) continue;\n                        if (blocked[v]) continue;\n                        if (dist1[v] == -1 || dist2[v] == -1) continue;\n                        pre = min(pre, (int)dist1[v] + (int)dist2[v]);\n                    }\n                    mv = min(mv, pre);\n                }\n\n                if (mv >= INF) continue;\n                int extra = (x != -1 && !used[x]) ? 1 : 0;\n                int baseScore = mv + extra;\n\n                if (lookahead && nxt != -1) {\n                    bfs_all(*afterG, target, -1, dist2);\n                    nextDist = (dist2[nxt] == -1 ? 1000 : (int)dist2[nxt]);\n                }\n\n                int heu = lookahead ? (3 * baseScore + nextDist) : baseScore;\n\n                if (heu < bestHeu ||\n                    (heu == bestHeu && baseScore < bestBase) ||\n                    (heu == bestHeu && baseScore == bestBase && x < bestx)) {\n                    bestHeu = heu;\n                    bestBase = baseScore;\n                    bestx = x;\n                }\n            }\n\n            asg[k] = bestx;\n            if (bestx != -1) used[bestx] = 1;\n            if (bestx != -1 && !blocked[bestx]) {\n                blocked[bestx] = 1;\n                haveG = false;\n            }\n            cur = target;\n        }\n\n        return asg;\n    }\n\n    Assign greedy_init_assign(bool lookahead) {\n        Assign base = none_assign();\n        return greedy_from_prefix(base, 1, lookahead);\n    }\n\n    Assign random_assign() {\n        Assign asg;\n        asg.fill(-1);\n        for (int k = 1; k < M; k++) {\n            int idx = (int)(rng() % cand[k].size());\n            asg[k] = cand[k][idx];\n        }\n        return asg;\n    }\n\n    pair<Assign, int> improve_assignment(Assign asg, int curScore, int passes) {\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 1);\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (time_up(0.10)) break;\n            shuffle(order.begin(), order.end(), rng);\n            bool improved = false;\n\n            for (int k : order) {\n                if (time_up(0.08)) break;\n\n                int old = asg[k];\n                int bestx = old;\n                int bestScore = curScore;\n\n                for (int x : cand[k]) {\n                    if (x == old) continue;\n                    asg[k] = x;\n                    int sc = eval_assignment(asg, bestScore);\n                    if (sc < bestScore) {\n                        bestScore = sc;\n                        bestx = x;\n                    }\n                }\n\n                asg[k] = bestx;\n                if (bestx != old) {\n                    curScore = bestScore;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {asg, curScore};\n    }\n\n    vector<Cmd> build_answer_assignment(const Assign& asg) {\n        vector<Cmd> ans;\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        vector<int> acts;\n        int cur = cells[0];\n        bool haveG = false;\n\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            if (!haveG) {\n                build_graph(blocked, g0);\n                haveG = true;\n            }\n\n            bfs_all(g0, cur, -1, dist0);\n            int direct = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            int pre = INF, bestV = -1;\n            bool add_new = (x != -1 && !blocked[x]);\n\n            if (add_new) {\n                bfs_all(g0, cur, target, dist1);\n\n                blocked[x] = 1;\n                build_graph(blocked, g1);\n                bfs_rev_all(g1, target, -1, dist2);\n                blocked[x] = 0;\n\n                int xr = row(x), xc = col(x);\n                for (int d = 0; d < 4; d++) {\n                    int vr = xr + dr[d], vc = xc + dc[d];\n                    if (!inside(vr, vc)) continue;\n                    int v = id(vr, vc);\n                    if (v == target) continue;\n                    if (blocked[v]) continue;\n                    if (dist1[v] == -1 || dist2[v] == -1) continue;\n                    int sc = (int)dist1[v] + (int)dist2[v];\n                    if (sc < pre) {\n                        pre = sc;\n                        bestV = v;\n                    }\n                }\n            }\n\n            bool use_pre = (pre < direct);\n\n            if (!use_pre) {\n                if (!bfs_path(g0, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n\n                if (add_new) {\n                    ans.push_back(alter_cmd(cur, x));\n                    blocked[x] = 1;\n                    g0 = g1;   // reuse graph of the new board\n                    haveG = true;\n                }\n            } else {\n                if (!bfs_path(g0, cur, bestV, target, acts)) return {};\n                append_acts(ans, acts);\n                cur = bestV;\n\n                ans.push_back(alter_cmd(cur, x));\n                blocked[x] = 1;\n\n                build_graph(blocked, g1);\n                if (!bfs_path(g1, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n\n                g0 = g1;\n                haveG = true;\n            }\n        }\n\n        return ans;\n    }\n\n    pair<bool, int> simulate(const vector<Cmd>& ans) const {\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        int cur = cells[0];\n        int t = 1;\n\n        auto dir_idx = [&](char d) -> int {\n            if (d == 'U') return 0;\n            if (d == 'D') return 1;\n            if (d == 'L') return 2;\n            return 3;\n        };\n\n        for (const auto& cmd : ans) {\n            int d = dir_idx(cmd.d);\n            if (cmd.a == 'M') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                if (blocked[v]) return {false, (int)ans.size()};\n                cur = v;\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'S') {\n                int rr = row(cur), cc = col(cur);\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int v = id(nr, nc);\n                    if (blocked[v]) break;\n                    rr = nr;\n                    cc = nc;\n                }\n                cur = id(rr, cc);\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'A') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                blocked[v] ^= 1;\n            } else {\n                return {false, (int)ans.size()};\n            }\n        }\n\n        bool ok = (t == M && (int)ans.size() <= 2 * N * M);\n        return {ok, (int)ans.size()};\n    }\n\n    vector<Cmd> build_empty_fallback() {\n        vector<Cmd> ans;\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n        build_graph(blocked, g0);\n\n        vector<int> acts;\n        int cur = cells[0];\n        for (int k = 1; k < M; k++) {\n            if (bfs_path(g0, cur, cells[k], -1, acts)) {\n                append_acts(ans, acts);\n            } else {\n                int cr = row(cur), cc = col(cur);\n                int tr = row(cells[k]), tc = col(cells[k]);\n                while (cr < tr) ans.push_back({'M', 'D'}), cr++;\n                while (cr > tr) ans.push_back({'M', 'U'}), cr--;\n                while (cc < tc) ans.push_back({'M', 'R'}), cc++;\n                while (cc > tc) ans.push_back({'M', 'L'}), cc--;\n            }\n            cur = cells[k];\n        }\n        return ans;\n    }\n\n    vector<Cmd> solve() {\n        Assign bestAsg = none_assign();\n        int bestScore = eval_assignment(bestAsg);\n\n        vector<Assign> seeds;\n        seeds.push_back(bestAsg);\n        seeds.push_back(heuristic_prev_assign());\n        seeds.push_back(greedy_init_assign(false));\n        if (!time_up(0.45)) seeds.push_back(greedy_init_assign(true));\n\n        for (auto seed : seeds) {\n            if (time_up(0.30)) break;\n            int sc = eval_assignment(seed);\n            auto res = improve_assignment(seed, sc, 2);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n        }\n\n        int iter = 0;\n        int suffix_trials = 0;\n\n        while (!time_up(0.18)) {\n            Assign cur = bestAsg;\n            int mode = iter % 6;\n\n            if (mode <= 2) {\n                int changes = 1 + (rng() % 3);\n                for (int t = 0; t < changes; t++) {\n                    int k = 1 + (int)(rng() % (M - 1));\n                    int idx = (int)(rng() % cand[k].size());\n                    cur[k] = cand[k][idx];\n                }\n                if (mode == 2 && M >= 3) {\n                    int k = 1 + (int)(rng() % (M - 2));\n                    int i1 = (int)(rng() % cand[k].size());\n                    int i2 = (int)(rng() % cand[k + 1].size());\n                    cur[k] = cand[k][i1];\n                    cur[k + 1] = cand[k + 1][i2];\n                }\n            } else if (suffix_trials < 8) {\n                int start_k = 1 + (int)(rng() % (M - 1));\n                bool lookahead = (mode == 3 || mode == 5);\n                cur = greedy_from_prefix(bestAsg, start_k, lookahead);\n                suffix_trials++;\n            } else {\n                cur = random_assign();\n            }\n\n            int sc = eval_assignment(cur, bestScore + 28);\n            if (sc < bestScore + 28) {\n                int passes = (mode >= 3 && mode <= 5) ? 2 : 1;\n                auto res = improve_assignment(cur, sc, passes);\n                if (res.second < bestScore) {\n                    bestScore = res.second;\n                    bestAsg = res.first;\n                }\n            }\n            iter++;\n        }\n\n        if (!time_up(0.08)) {\n            auto res = improve_assignment(bestAsg, bestScore, 1);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n        }\n\n        vector<Cmd> ans = build_answer_assignment(bestAsg);\n        auto [ok, len] = simulate(ans);\n\n        if (!ok) {\n            Assign none = none_assign();\n            ans = build_answer_assignment(none);\n            auto [ok2, len2] = simulate(ans);\n            if (!ok2) {\n                ans.clear();\n                int cur = cells[0];\n                for (int i = 1; i < M; i++) {\n                    int tr = row(cells[i]), tc = col(cells[i]);\n                    int cr = row(cur), cc = col(cur);\n                    while (cr < tr) ans.push_back({'M', 'D'}), cr++;\n                    while (cr > tr) ans.push_back({'M', 'U'}), cr--;\n                    while (cc < tc) ans.push_back({'M', 'R'}), cc++;\n                    while (cc > tc) ans.push_back({'M', 'L'}), cc--;\n                    cur = cells[i];\n                }\n            }\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<Point> pts(M);\n    for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n    Solver solver(N, M, pts);\n    vector<Cmd> ans = solver.solve();\n\n    for (auto &c : ans) {\n        cout << c.a << ' ' << c.d << '\\n';\n    }\n    return 0;\n}"},"16":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ld = long double;\nstatic constexpr int BOARD = 10000;\nstatic constexpr ld INF_CAP = 1e30L;\n\nstruct Rect {\n    int l, b, r, t; // [l, r) x [b, t)\n    int area() const { return (r - l) * (t - b); }\n};\n\nenum Action {\n    EXP_L = 0,\n    EXP_R = 1,\n    EXP_B = 2,\n    EXP_T = 3,\n    SHR_L = 4,\n    SHR_R = 5,\n    SHR_B = 6,\n    SHR_T = 7\n};\n\nstatic constexpr int MASK_EXP =\n    (1 << EXP_L) | (1 << EXP_R) | (1 << EXP_B) | (1 << EXP_T);\nstatic constexpr int MASK_SHR =\n    (1 << SHR_L) | (1 << SHR_R) | (1 << SHR_B) | (1 << SHR_T);\nstatic constexpr int MASK_ALL = MASK_EXP | MASK_SHR;\n\nstruct Move {\n    bool valid = false;\n    int action = 0;\n    int delta = 0;\n    int freecap = 0;\n    int prio = 0;\n    ld gain = 0;\n    ld sec = 0;\n};\n\nstruct PairCand {\n    bool valid = false;\n    int i = -1, j = -1;\n    Rect ri, rj;\n    ld gain = 0;\n    ld sec = 0;\n};\n\nstruct Params {\n    vector<ld> caps;\n    int order_mode = 0;\n    bool reverse_axis = false;\n    array<int, 8> action_prio{};\n};\n\nstruct BSPParams {\n    ld err_w = 0.5L;\n    ld aspect_w = 0.02L;\n    ld step_w = 0.01L;\n    int orient_bias = 0; // -1: horizontal, +1: vertical\n    int top_try = 8;\n    bool smart_bias = true;\n};\n\nstruct SplitCand {\n    bool vertical = true;\n    int cut = 0;\n    vector<int> left, right;\n    ld score = 0;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int mod) {\n        return (int)(next_u64() % (uint64_t)mod);\n    }\n    ld uniform() {\n        return (next_u64() >> 11) * (1.0L / (1ULL << 53));\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n};\n\nstruct Solver {\n    int n;\n    vector<int> xs, ys, rs;\n    vector<ld> sqrs;\n    vector<int> nearest_idx;\n    XorShift64 rng;\n    chrono::steady_clock::time_point start_time;\n\n    static bool overlap1d(int l1, int r1, int l2, int r2) {\n        return max(l1, l2) < min(r1, r2);\n    }\n\n    static int ceil_div_int(int a, int b) {\n        return (a + b - 1) / b;\n    }\n\n    ld satisfaction(ld need, ld area) const {\n        if (need <= 0 || area <= 0) return 0;\n        ld t = min(need, area) / max(need, area);\n        ld u = 1.0L - t;\n        return 1.0L - u * u;\n    }\n\n    ld total_score(const vector<Rect>& rects) const {\n        ld res = 0;\n        for (int i = 0; i < n; ++i) res += satisfaction((ld)rs[i], (ld)rects[i].area());\n        return res;\n    }\n\n    long long occupied_area(const vector<Rect>& rects) const {\n        long long s = 0;\n        for (auto &r : rects) s += r.area();\n        return s;\n    }\n\n    vector<Rect> initial_rects() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; ++i) rects[i] = {xs[i], ys[i], xs[i] + 1, ys[i] + 1};\n        return rects;\n    }\n\n    void apply_move(Rect& rc, int action, int delta) const {\n        switch (action) {\n            case EXP_L: rc.l -= delta; break;\n            case EXP_R: rc.r += delta; break;\n            case EXP_B: rc.b -= delta; break;\n            case EXP_T: rc.t += delta; break;\n            case SHR_L: rc.l += delta; break;\n            case SHR_R: rc.r -= delta; break;\n            case SHR_B: rc.b += delta; break;\n            case SHR_T: rc.t -= delta; break;\n        }\n    }\n\n    ld rect_sec_metric(int i, const Rect& rc) const {\n        int w = rc.r - rc.l;\n        int h = rc.t - rc.b;\n        int area = w * h;\n        int need = rs[i];\n        int nL = xs[i] - rc.l;\n        int nR = rc.r - (xs[i] + 1);\n        int nB = ys[i] - rc.b;\n        int nT = rc.t - (ys[i] + 1);\n        ld aspect = (ld)max(w, h) / (ld)min(w, h);\n        ld imbalance = (ld)(abs(nL - nR) + abs(nB - nT)) / (ld)(w + h);\n        ld err = fabsl((ld)area - (ld)need) / (ld)need;\n        return err + 0.01L * aspect + 0.02L * imbalance;\n    }\n\n    ld total_secondary(const vector<Rect>& rects) const {\n        ld res = 0;\n        for (int i = 0; i < n; ++i) res += rect_sec_metric(i, rects[i]);\n        return res;\n    }\n\n    bool better_solution(ld sc1, ld sec1, ld sc2, ld sec2) const {\n        const ld EPS = 1e-18L;\n        if (sc1 > sc2 + EPS) return true;\n        if (sc1 + EPS < sc2) return false;\n        return sec1 + 1e-15L < sec2;\n    }\n\n    bool better_move(const Move& a, const Move& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const ld EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        if (a.delta < b.delta) return true;\n        if (a.delta > b.delta) return false;\n        if (a.freecap > b.freecap) return true;\n        if (a.freecap < b.freecap) return false;\n        return a.prio < b.prio;\n    }\n\n    bool better_pair(const PairCand& a, const PairCand& b) const {\n        if (!a.valid) return false;\n        if (!b.valid) return true;\n        const ld EPS = 1e-18L;\n        if (a.gain > b.gain + EPS) return true;\n        if (a.gain + EPS < b.gain) return false;\n        if (a.sec + 1e-15L < b.sec) return true;\n        if (a.sec > b.sec + 1e-15L) return false;\n        return make_pair(a.i, a.j) < make_pair(b.i, b.j);\n    }\n\n    void compute_expand_limits(int i, const vector<Rect>& rects,\n                               int& maxL, int& maxR, int& maxB, int& maxT) const {\n        const Rect& a = rects[i];\n        int limL = 0, limR = BOARD, limB = 0, limT = BOARD;\n        for (int j = 0; j < n; ++j) if (j != i) {\n            const Rect& o = rects[j];\n            if (overlap1d(a.b, a.t, o.b, o.t)) {\n                if (o.r <= a.l) limL = max(limL, o.r);\n                if (o.l >= a.r) limR = min(limR, o.l);\n            }\n            if (overlap1d(a.l, a.r, o.l, o.r)) {\n                if (o.t <= a.b) limB = max(limB, o.t);\n                if (o.b >= a.t) limT = min(limT, o.b);\n            }\n        }\n        maxL = a.l - limL;\n        maxR = limR - a.r;\n        maxB = a.b - limB;\n        maxT = limT - a.t;\n    }\n\n    static void add_target_lengths(vector<int>& v, ld target, int cur, bool expand_mode) {\n        const ld eps = 1e-12L;\n        int f = (int)floor(target + eps);\n        int c = (int)ceil(target - eps);\n        if (expand_mode) {\n            if (f > cur) v.push_back(f);\n            if (c > cur) v.push_back(c);\n        } else {\n            if (f >= 1 && f < cur) v.push_back(f);\n            if (c >= 1 && c < cur) v.push_back(c);\n        }\n    }\n\n    Move best_move_for_rect(int i, const vector<Rect>& rects,\n                            ld shape_cap, bool aggressive,\n                            const array<int, 8>& prio_map,\n                            int allowed_mask) const {\n        const Rect& cur = rects[i];\n        int w = cur.r - cur.l;\n        int h = cur.t - cur.b;\n        int area = w * h;\n        int need = rs[i];\n        ld cur_sat = satisfaction((ld)need, (ld)area);\n\n        int maxL, maxR, maxB, maxT;\n        compute_expand_limits(i, rects, maxL, maxR, maxB, maxT);\n\n        int marginL = xs[i] - cur.l;\n        int marginR = cur.r - (xs[i] + 1);\n        int marginB = ys[i] - cur.b;\n        int marginT = cur.t - (ys[i] + 1);\n\n        vector<Move> cands;\n\n        auto push_candidate = [&](int action, int delta, int freecap) {\n            if (!(allowed_mask & (1 << action))) return;\n            if (delta <= 0) return;\n            for (const auto& mv : cands) {\n                if (mv.action == action && mv.delta == delta) return;\n            }\n            Rect nr = cur;\n            apply_move(nr, action, delta);\n            int nw = nr.r - nr.l;\n            int nh = nr.t - nr.b;\n            int ns = nw * nh;\n            ld g = satisfaction((ld)need, (ld)ns) - cur_sat;\n            if (g <= 1e-18L) return;\n\n            int nL = xs[i] - nr.l;\n            int nR = nr.r - (xs[i] + 1);\n            int nB = ys[i] - nr.b;\n            int nT = nr.t - (ys[i] + 1);\n\n            ld aspect = (ld)max(nw, nh) / (ld)min(nw, nh);\n            ld imbalance = (ld)(abs(nL - nR) + abs(nB - nT)) / (ld)(nw + nh);\n            ld err = fabsl((ld)ns - (ld)need) / (ld)need;\n            ld sec = err + 0.01L * aspect + 0.02L * imbalance;\n\n            Move mv;\n            mv.valid = true;\n            mv.action = action;\n            mv.delta = delta;\n            mv.freecap = freecap;\n            mv.prio = prio_map[action];\n            mv.gain = g;\n            mv.sec = sec;\n            cands.push_back(mv);\n        };\n\n        if (area < need) {\n            ld exactW = (ld)need / (ld)h;\n            ld limitedW = min(exactW, sqrs[i] * shape_cap);\n            vector<int> wtars;\n            add_target_lengths(wtars, limitedW, w, true);\n            add_target_lengths(wtars, exactW, w, true);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_expand_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = Wtar - w;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactW - 1e-12L) > w + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactW - (ld)w - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side(EXP_L, maxL);\n            gen_expand_side(EXP_R, maxR);\n\n            ld exactH = (ld)need / (ld)w;\n            ld limitedH = min(exactH, sqrs[i] * shape_cap);\n            vector<int> htars;\n            add_target_lengths(htars, limitedH, h, true);\n            add_target_lengths(htars, exactH, h, true);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_expand_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = Htar - h;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                if (!added || (int)ceil(exactH - 1e-12L) > h + maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n                if (aggressive && maxd >= 1) {\n                    int d = (int)ceil(exactH - (ld)h - 1e-12L);\n                    if (d > 0) push_candidate(action, min(d, maxd), maxd);\n                }\n            };\n            gen_expand_side_v(EXP_B, maxB);\n            gen_expand_side_v(EXP_T, maxT);\n        } else if (area > need) {\n            ld exactW = (ld)need / (ld)h;\n            vector<int> wtars;\n            add_target_lengths(wtars, exactW, w, false);\n            sort(wtars.begin(), wtars.end());\n            wtars.erase(unique(wtars.begin(), wtars.end()), wtars.end());\n\n            auto gen_shrink_side = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Wtar : wtars) {\n                    int d = w - Wtar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)w - exactW - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side(SHR_L, marginL);\n            gen_shrink_side(SHR_R, marginR);\n\n            ld exactH = (ld)need / (ld)w;\n            vector<int> htars;\n            add_target_lengths(htars, exactH, h, false);\n            sort(htars.begin(), htars.end());\n            htars.erase(unique(htars.begin(), htars.end()), htars.end());\n\n            auto gen_shrink_side_v = [&](int action, int maxd) {\n                if (!(allowed_mask & (1 << action))) return;\n                if (maxd <= 0) return;\n                bool added = false;\n                for (int Htar : htars) {\n                    int d = h - Htar;\n                    if (d > 0) {\n                        push_candidate(action, min(d, maxd), maxd);\n                        added = true;\n                    }\n                }\n                int exactd = (int)ceil((ld)h - exactH - 1e-12L);\n                if (!added || exactd > maxd) {\n                    push_candidate(action, maxd, maxd);\n                }\n            };\n            gen_shrink_side_v(SHR_B, marginB);\n            gen_shrink_side_v(SHR_T, marginT);\n        }\n\n        Move best;\n        for (const auto& mv : cands) {\n            if (better_move(mv, best)) best = mv;\n        }\n        return best;\n    }\n\n    vector<int> build_order(const vector<Rect>& rects, int mode, bool reverse_axis) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n\n        if (mode == 0) return ord;\n\n        if (mode == 1) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return rs[a] > rs[b];\n            });\n        } else if (mode == 2) {\n            vector<ld> key(n);\n            for (int i = 0; i < n; ++i) key[i] = 1.0L - satisfaction((ld)rs[i], (ld)rects[i].area());\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        } else if (mode == 3) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] < xs[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return xs[a] > xs[b];\n                });\n            }\n        } else if (mode == 4) {\n            if (!reverse_axis) {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] < ys[b];\n                });\n            } else {\n                stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    return ys[a] > ys[b];\n                });\n            }\n        } else if (mode == 5) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rs[a] - rects[a].area()) > (rs[b] - rects[b].area());\n            });\n        } else if (mode == 6) {\n            stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return (rects[a].area() - rs[a]) > (rects[b].area() - rs[b]);\n            });\n        }\n\n        return ord;\n    }\n\n    static ld log_aspect(int w, int h) {\n        ld a = (ld)max(w, h) / (ld)min(w, h);\n        return log(a);\n    }\n\n    vector<SplitCand> generate_bsp_candidates(const vector<int>& ids,\n                                              int lx, int ly, int rx, int ry,\n                                              const BSPParams& par,\n                                              bool optimize_score) {\n        vector<SplitCand> res;\n        int m = (int)ids.size();\n        if (m <= 1) return res;\n\n        int W = rx - lx, H = ry - ly;\n        ld regionArea = (ld)W * (ld)H;\n\n        vector<int> xord = ids, yord = ids;\n        sort(xord.begin(), xord.end(), [&](int a, int b) {\n            if (xs[a] != xs[b]) return xs[a] < xs[b];\n            return ys[a] < ys[b];\n        });\n        sort(yord.begin(), yord.end(), [&](int a, int b) {\n            if (ys[a] != ys[b]) return ys[a] < ys[b];\n            return xs[a] < xs[b];\n        });\n\n        auto make_score = [&](bool vertical, int cut,\n                              const vector<int>& left, const vector<int>& right,\n                              long long reqL, long long reqTot) -> SplitCand {\n            SplitCand c;\n            c.vertical = vertical;\n            c.cut = cut;\n            c.left = left;\n            c.right = right;\n\n            long long reqR = reqTot - reqL;\n\n            ld areaL, areaR;\n            int w1, h1, w2, h2, step;\n            if (vertical) {\n                w1 = cut - lx; h1 = H;\n                w2 = rx - cut; h2 = H;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = H;\n            } else {\n                w1 = W; h1 = cut - ly;\n                w2 = W; h2 = ry - cut;\n                areaL = (ld)w1 * h1;\n                areaR = (ld)w2 * h2;\n                step = W;\n            }\n\n            ld proxy = (ld)left.size() * satisfaction((ld)reqL, areaL)\n                     + (ld)right.size() * satisfaction((ld)reqR, areaR);\n\n            ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n            ld err = fabsl(areaL - scaledL) / regionArea;\n            ld shape = log_aspect(w1, h1) + log_aspect(w2, h2);\n\n            ld score;\n            if (optimize_score) {\n                score = proxy\n                      - par.err_w * err\n                      - par.aspect_w * shape\n                      - par.step_w * ((ld)step / (ld)BOARD);\n\n                if (par.orient_bias == 1 && vertical) score += 1e-3L;\n                if (par.orient_bias == -1 && !vertical) score += 1e-3L;\n                if (par.smart_bias) {\n                    if (W > H && vertical) score += 5e-4L;\n                    if (H > W && !vertical) score += 5e-4L;\n                }\n                score += rng.uniform() * 1e-6L;\n            } else {\n                score = -0.05L * shape - 0.001L * ((ld)step / (ld)BOARD) + rng.uniform() * 1e-6L;\n            }\n            c.score = score;\n            return c;\n        };\n\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[xord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int xL = xs[xord[k - 1]];\n                int xR = xs[xord[k]];\n                int lo = max(lx + 1, xL + 1);\n                int hi = min(rx - 1, xR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, lx + ceil_div_int(k, H));\n                int ahi = min(hi, rx - ceil_div_int(m - k, H));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)lx + scaledL / (ld)H;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    c = max(c, alo);\n                    c = min(c, ahi);\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(xord.begin(), xord.begin() + k);\n                vector<int> right(xord.begin() + k, xord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(true, cut, left, right, reqL, reqTot));\n                }\n            }\n        }\n\n        {\n            vector<long long> pref(m + 1, 0);\n            for (int i = 0; i < m; ++i) pref[i + 1] = pref[i] + rs[yord[i]];\n            long long reqTot = pref[m];\n\n            for (int k = 1; k < m; ++k) {\n                int yL = ys[yord[k - 1]];\n                int yR = ys[yord[k]];\n                int lo = max(ly + 1, yL + 1);\n                int hi = min(ry - 1, yR);\n                if (lo > hi) continue;\n\n                int alo = max(lo, ly + ceil_div_int(k, W));\n                int ahi = min(hi, ry - ceil_div_int(m - k, W));\n                if (alo > ahi) continue;\n\n                long long reqL = pref[k];\n                ld scaledL = regionArea * (ld)reqL / (ld)reqTot;\n                ld ideal = (ld)ly + scaledL / (ld)W;\n\n                vector<int> cuts;\n                auto add_cut = [&](int c) {\n                    c = max(c, alo);\n                    c = min(c, ahi);\n                    cuts.push_back(c);\n                };\n                add_cut((int)floor(ideal + 1e-12L));\n                add_cut((int)ceil(ideal - 1e-12L));\n                add_cut(alo);\n                add_cut(ahi);\n                add_cut((alo + ahi) / 2);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n                vector<int> left(yord.begin(), yord.begin() + k);\n                vector<int> right(yord.begin() + k, yord.end());\n\n                for (int cut : cuts) {\n                    res.push_back(make_score(false, cut, left, right, reqL, reqTot));\n                }\n            }\n        }\n\n        sort(res.begin(), res.end(), [&](const SplitCand& a, const SplitCand& b) {\n            return a.score > b.score;\n        });\n        return res;\n    }\n\n    bool partition_rec_simple(const vector<int>& ids,\n                              int lx, int ly, int rx, int ry,\n                              vector<Rect>& out) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        BSPParams dummy;\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, dummy, false);\n        if (cands.empty()) return false;\n\n        for (const auto& c : cands) {\n            if (c.vertical) {\n                if (partition_rec_simple(c.left, lx, ly, c.cut, ry, out) &&\n                    partition_rec_simple(c.right, c.cut, ly, rx, ry, out)) return true;\n            } else {\n                if (partition_rec_simple(c.left, lx, ly, rx, c.cut, out) &&\n                    partition_rec_simple(c.right, lx, c.cut, rx, ry, out)) return true;\n            }\n        }\n        return false;\n    }\n\n    bool partition_rec_opt(const vector<int>& ids,\n                           int lx, int ly, int rx, int ry,\n                           vector<Rect>& out,\n                           const BSPParams& par,\n                           int depth) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = {lx, ly, rx, ry};\n            return true;\n        }\n\n        auto cands = generate_bsp_candidates(ids, lx, ly, rx, ry, par, true);\n        if (cands.empty()) {\n            return partition_rec_simple(ids, lx, ly, rx, ry, out);\n        }\n\n        int limit = min((int)cands.size(), par.top_try + (depth <= 2 ? 4 : 0));\n        for (int idx = 0; idx < limit; ++idx) {\n            const auto& c = cands[idx];\n            bool ok;\n            if (c.vertical) {\n                ok = partition_rec_opt(c.left, lx, ly, c.cut, ry, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, c.cut, ly, rx, ry, out, par, depth + 1);\n            } else {\n                ok = partition_rec_opt(c.left, lx, ly, rx, c.cut, out, par, depth + 1) &&\n                     partition_rec_opt(c.right, lx, c.cut, rx, ry, out, par, depth + 1);\n            }\n            if (ok) return true;\n        }\n\n        return partition_rec_simple(ids, lx, ly, rx, ry, out);\n    }\n\n    vector<Rect> build_partition_solution(const BSPParams& par) {\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        vector<Rect> rects(n, {0, 0, 0, 0});\n        bool ok = partition_rec_opt(ids, 0, 0, BOARD, BOARD, rects, par, 0);\n        if (!ok) return initial_rects();\n        for (int i = 0; i < n; ++i) {\n            if (!(0 <= rects[i].l && rects[i].l < rects[i].r && rects[i].r <= BOARD &&\n                  0 <= rects[i].b && rects[i].b < rects[i].t && rects[i].t <= BOARD)) {\n                return initial_rects();\n            }\n            if (!(rects[i].l <= xs[i] && xs[i] < rects[i].r &&\n                  rects[i].b <= ys[i] && ys[i] < rects[i].t)) {\n                return initial_rects();\n            }\n        }\n        return rects;\n    }\n\n    Params random_constructive_params() {\n        Params p;\n        ld c0 = 0.85L + 0.40L * rng.uniform();\n        p.caps = {c0, c0 * 1.35L, c0 * 1.8L, c0 * 2.5L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.25L) p.order_mode = 0;\n        else if (u < 0.48L) p.order_mode = 1;\n        else if (u < 0.70L) p.order_mode = 2;\n        else if (u < 0.85L) p.order_mode = 5;\n        else if (u < 0.925L) p.order_mode = 3;\n        else p.order_mode = 4;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_perturb_params() {\n        Params p;\n        ld c0 = 0.95L + 0.55L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, c0 * 2.2L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 2;\n        else if (u < 0.70L) p.order_mode = 5;\n        else if (u < 0.90L) p.order_mode = 6;\n        else p.order_mode = 1;\n\n        p.reverse_axis = (rng.next_int(2) == 1);\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params random_partition_params() {\n        Params p;\n        ld c0 = 1.00L + 0.35L * rng.uniform();\n        p.caps = {c0, c0 * 1.45L, INF_CAP, INF_CAP};\n\n        ld u = rng.uniform();\n        if (u < 0.40L) p.order_mode = 6;\n        else if (u < 0.75L) p.order_mode = 2;\n        else if (u < 0.92L) p.order_mode = 5;\n        else p.order_mode = 1;\n\n        p.reverse_axis = false;\n        p.action_prio = random_action_priority();\n        return p;\n    }\n\n    Params polish_params() {\n        Params p;\n        p.caps = {1.05L, 1.35L, 1.8L, INF_CAP, INF_CAP};\n        p.order_mode = 2;\n        p.reverse_axis = false;\n        for (int i = 0; i < 8; ++i) p.action_prio[i] = i;\n        return p;\n    }\n\n    array<int, 8> random_action_priority() {\n        vector<int> ord(8);\n        iota(ord.begin(), ord.end(), 0);\n        rng.shuffle_vec(ord);\n        array<int, 8> pr{};\n        for (int i = 0; i < 8; ++i) pr[ord[i]] = i;\n        return pr;\n    }\n\n    BSPParams random_bsp_params() {\n        BSPParams p;\n        p.err_w = 0.20L + 0.80L * rng.uniform();\n        p.aspect_w = 0.008L + 0.030L * rng.uniform();\n        p.step_w = 0.000L + 0.030L * rng.uniform();\n        p.orient_bias = rng.next_int(3) - 1;\n        p.top_try = 5 + rng.next_int(6);\n        p.smart_bias = true;\n        return p;\n    }\n\n    int weighted_pick(const vector<ld>& w, const vector<char>& banned) {\n        ld sum = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) sum += w[i];\n        if (sum <= 0) {\n            vector<int> cand;\n            for (int i = 0; i < n; ++i) if (!banned[i]) cand.push_back(i);\n            if (cand.empty()) return -1;\n            return cand[rng.next_int((int)cand.size())];\n        }\n        ld z = rng.uniform() * sum;\n        ld acc = 0;\n        for (int i = 0; i < n; ++i) if (!banned[i]) {\n            acc += w[i];\n            if (acc >= z) return i;\n        }\n        for (int i = n - 1; i >= 0; --i) if (!banned[i]) return i;\n        return -1;\n    }\n\n    vector<Rect> perturb_from_best(const vector<Rect>& best) {\n        vector<Rect> seed = best;\n        vector<ld> w(n);\n        for (int i = 0; i < n; ++i) {\n            w[i] = 0.01L + (1.0L - satisfaction((ld)rs[i], (ld)best[i].area()));\n        }\n        vector<char> banned(n, 0);\n        int k = 1 + rng.next_int(min(5, n));\n\n        auto reset_rect = [&](int idx) {\n            if (idx < 0) return;\n            seed[idx] = {xs[idx], ys[idx], xs[idx] + 1, ys[idx] + 1};\n            banned[idx] = 1;\n        };\n\n        for (int it = 0; it < k; ++it) {\n            int idx = weighted_pick(w, banned);\n            if (idx < 0) break;\n            reset_rect(idx);\n            if (nearest_idx[idx] != -1 && rng.next_int(100) < 55) {\n                reset_rect(nearest_idx[idx]);\n            }\n        }\n        return seed;\n    }\n\n    static void add_unique_int(vector<int>& v, int x) {\n        v.push_back(x);\n    }\n\n    bool choose_interval_around_anchor(int L, int R, int anchor, int len, int& outL) const {\n        int lo = max(L, anchor - len + 1);\n        int hi = min(anchor, R - len);\n        if (lo > hi) return false;\n        int ideal = anchor - (len - 1) / 2;\n        if (ideal < lo) ideal = lo;\n        if (ideal > hi) ideal = hi;\n        outL = ideal;\n        return true;\n    }\n\n    pair<bool, Rect> best_rebuild_candidate(int i, const vector<Rect>& rects, bool allow_equal) const {\n        const Rect& cur = rects[i];\n        Rect best = cur;\n        ld best_sat = satisfaction((ld)rs[i], (ld)cur.area());\n        ld best_sec = rect_sec_metric(i, cur);\n\n        auto consider = [&](const Rect& nr) {\n            if (!(0 <= nr.l && nr.l < nr.r && nr.r <= BOARD &&\n                  0 <= nr.b && nr.b < nr.t && nr.t <= BOARD)) return;\n            if (!(nr.l <= xs[i] && xs[i] < nr.r && nr.b <= ys[i] && ys[i] < nr.t)) return;\n\n            ld nsat = satisfaction((ld)rs[i], (ld)nr.area());\n            ld nsec = rect_sec_metric(i, nr);\n\n            const ld EPS = 1e-18L;\n            bool better = false;\n            if (nsat > best_sat + EPS) better = true;\n            else if (allow_equal && fabsl(nsat - best_sat) <= EPS && nsec + 1e-15L < best_sec) better = true;\n\n            if (better) {\n                best = nr;\n                best_sat = nsat;\n                best_sec = nsec;\n            }\n        };\n\n        {\n            vector<int> Bs, Ts;\n            Bs.reserve(n + 4);\n            Ts.reserve(n + 4);\n            add_unique_int(Bs, 0);\n            add_unique_int(Bs, cur.b);\n            add_unique_int(Ts, BOARD);\n            add_unique_int(Ts, cur.t);\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.t <= ys[i]) add_unique_int(Bs, o.t);\n                if (o.b >= ys[i] + 1) add_unique_int(Ts, o.b);\n            }\n            sort(Bs.begin(), Bs.end());\n            Bs.erase(unique(Bs.begin(), Bs.end()), Bs.end());\n            sort(Ts.begin(), Ts.end());\n            Ts.erase(unique(Ts.begin(), Ts.end()), Ts.end());\n\n            int curW = cur.r - cur.l;\n            for (int b : Bs) {\n                if (b > ys[i]) continue;\n                for (int t : Ts) {\n                    if (t < ys[i] + 1) continue;\n                    if (b >= t) continue;\n\n                    int L = 0, R = BOARD;\n                    bool valid = true;\n                    for (int j = 0; j < n; ++j) if (j != i) {\n                        const Rect& o = rects[j];\n                        if (!overlap1d(b, t, o.b, o.t)) continue;\n\n                        if (overlap1d(o.l, o.r, xs[i], xs[i] + 1)) {\n                            valid = false;\n                            break;\n                        }\n                        if (o.r <= xs[i]) L = max(L, o.r);\n                        else if (o.l >= xs[i] + 1) R = min(R, o.l);\n                        else {\n                            valid = false;\n                            break;\n                        }\n                    }\n                    if (!valid || L >= R) continue;\n\n                    int h = t - b;\n                    int wcap = R - L;\n                    if (wcap <= 0) continue;\n\n                    vector<int> candW;\n                    auto addW = [&](int W) {\n                        if (1 <= W && W <= wcap) candW.push_back(W);\n                    };\n                    ld tw = (ld)rs[i] / (ld)h;\n                    addW((int)floor(tw + 1e-12L));\n                    addW((int)ceil(tw - 1e-12L));\n                    addW((int)llround(tw));\n                    addW(curW);\n                    addW(wcap);\n                    sort(candW.begin(), candW.end());\n                    candW.erase(unique(candW.begin(), candW.end()), candW.end());\n\n                    for (int W : candW) {\n                        int l;\n                        if (!choose_interval_around_anchor(L, R, xs[i], W, l)) continue;\n                        Rect nr{l, b, l + W, t};\n                        consider(nr);\n                    }\n                }\n            }\n        }\n\n        {\n            vector<int> Ls, Rs;\n            Ls.reserve(n + 4);\n            Rs.reserve(n + 4);\n            add_unique_int(Ls, 0);\n            add_unique_int(Ls, cur.l);\n            add_unique_int(Rs, BOARD);\n            add_unique_int(Rs, cur.r);\n            for (int j = 0; j < n; ++j) if (j != i) {\n                const Rect& o = rects[j];\n                if (o.r <= xs[i]) add_unique_int(Ls, o.r);\n                if (o.l >= xs[i] + 1) add_unique_int(Rs, o.l);\n            }\n            sort(Ls.begin(), Ls.end());\n            Ls.erase(unique(Ls.begin(), Ls.end()), Ls.end());\n            sort(Rs.begin(), Rs.end());\n            Rs.erase(unique(Rs.begin(), Rs.end()), Rs.end());\n\n            int curH = cur.t - cur.b;\n            for (int l : Ls) {\n                if (l > xs[i]) continue;\n                for (int r : Rs) {\n                    if (r < xs[i] + 1) continue;\n                    if (l >= r) continue;\n\n                    int B = 0, T = BOARD;\n                    bool valid = true;\n                    for (int j = 0; j < n; ++j) if (j != i) {\n                        const Rect& o = rects[j];\n                        if (!overlap1d(l, r, o.l, o.r)) continue;\n\n                        if (overlap1d(o.b, o.t, ys[i], ys[i] + 1)) {\n                            valid = false;\n                            break;\n                        }\n                        if (o.t <= ys[i]) B = max(B, o.t);\n                        else if (o.b >= ys[i] + 1) T = min(T, o.b);\n                        else {\n                            valid = false;\n                            break;\n                        }\n                    }\n                    if (!valid || B >= T) continue;\n\n                    int w = r - l;\n                    int hcap = T - B;\n                    if (hcap <= 0) continue;\n\n                    vector<int> candH;\n                    auto addH = [&](int H) {\n                        if (1 <= H && H <= hcap) candH.push_back(H);\n                    };\n                    ld th = (ld)rs[i] / (ld)w;\n                    addH((int)floor(th + 1e-12L));\n                    addH((int)ceil(th - 1e-12L));\n                    addH((int)llround(th));\n                    addH(curH);\n                    addH(hcap);\n                    sort(candH.begin(), candH.end());\n                    candH.erase(unique(candH.begin(), candH.end()), candH.end());\n\n                    for (int H : candH) {\n                        int b;\n                        if (!choose_interval_around_anchor(B, T, ys[i], H, b)) continue;\n                        Rect nr{l, b, r, b + H};\n                        consider(nr);\n                    }\n                }\n            }\n        }\n\n        if (best.l == cur.l && best.b == cur.b && best.r == cur.r && best.t == cur.t) {\n            return {false, cur};\n        }\n        return {true, best};\n    }\n\n    PairCand best_pair_rebuild_candidate(int i, int j, const vector<Rect>& rects, bool allow_equal) const {\n        PairCand res;\n        if (i == j) return res;\n\n        const Rect& a0 = rects[i];\n        const Rect& b0 = rects[j];\n        int L = min(a0.l, b0.l);\n        int B = min(a0.b, b0.b);\n        int R = max(a0.r, b0.r);\n        int T = max(a0.t, b0.t);\n\n        for (int k = 0; k < n; ++k) if (k != i && k != j) {\n            const Rect& o = rects[k];\n            if (overlap1d(L, R, o.l, o.r) && overlap1d(B, T, o.b, o.t)) {\n                return res;\n            }\n        }\n\n        ld cur_sat = satisfaction((ld)rs[i], (ld)a0.area()) + satisfaction((ld)rs[j], (ld)b0.area());\n        ld cur_sec = rect_sec_metric(i, a0) + rect_sec_metric(j, b0);\n\n        ld best_sat = cur_sat;\n        ld best_sec = cur_sec;\n        Rect best_i = a0, best_j = b0;\n\n        auto consider = [&](const Rect& ri, const Rect& rj) {\n            if (!(0 <= ri.l && ri.l < ri.r && ri.r <= BOARD && 0 <= ri.b && ri.b < ri.t && ri.t <= BOARD)) return;\n            if (!(0 <= rj.l && rj.l < rj.r && rj.r <= BOARD && 0 <= rj.b && rj.b < rj.t && rj.t <= BOARD)) return;\n            if (!(ri.l <= xs[i] && xs[i] < ri.r && ri.b <= ys[i] && ys[i] < ri.t)) return;\n            if (!(rj.l <= xs[j] && xs[j] < rj.r && rj.b <= ys[j] && ys[j] < rj.t)) return;\n            if (overlap1d(ri.l, ri.r, rj.l, rj.r) && overlap1d(ri.b, ri.t, rj.b, rj.t)) return;\n\n            ld nsat = satisfaction((ld)rs[i], (ld)ri.area()) + satisfaction((ld)rs[j], (ld)rj.area());\n            ld nsec = rect_sec_metric(i, ri) + rect_sec_metric(j, rj);\n\n            const ld EPS = 1e-18L;\n            bool better = false;\n            if (nsat > best_sat + EPS) better = true;\n            else if (allow_equal && fabsl(nsat - best_sat) <= EPS && nsec + 1e-15L < best_sec) better = true;\n\n            if (better) {\n                best_sat = nsat;\n                best_sec = nsec;\n                best_i = ri;\n                best_j = rj;\n            }\n        };\n\n        auto push_cut = [&](vector<int>& v, int c, int lo, int hi) {\n            if (c < lo) c = lo;\n            if (c > hi) c = hi;\n            v.push_back(c);\n        };\n\n        if (xs[i] < xs[j]) {\n            int lo = xs[i] + 1;\n            int hi = xs[j];\n            if (lo <= hi) {\n                int H = T - B;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)L + (ld)rs[i] / (ld)H;\n                ld z2 = (ld)R - (ld)rs[j] / (ld)H;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (a0.r == b0.l) push_cut(cuts, a0.r, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, B, c, T}, Rect{c, B, R, T});\n                }\n            }\n        } else if (xs[j] < xs[i]) {\n            int lo = xs[j] + 1;\n            int hi = xs[i];\n            if (lo <= hi) {\n                int H = T - B;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)L + (ld)rs[j] / (ld)H;\n                ld z2 = (ld)R - (ld)rs[i] / (ld)H;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (b0.r == a0.l) push_cut(cuts, b0.r, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{c, B, R, T}, Rect{L, B, c, T});\n                }\n            }\n        }\n\n        if (ys[i] < ys[j]) {\n            int lo = ys[i] + 1;\n            int hi = ys[j];\n            if (lo <= hi) {\n                int W = R - L;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)B + (ld)rs[i] / (ld)W;\n                ld z2 = (ld)T - (ld)rs[j] / (ld)W;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (a0.t == b0.b) push_cut(cuts, a0.t, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, B, R, c}, Rect{L, c, R, T});\n                }\n            }\n        } else if (ys[j] < ys[i]) {\n            int lo = ys[j] + 1;\n            int hi = ys[i];\n            if (lo <= hi) {\n                int W = R - L;\n                vector<int> cuts;\n                push_cut(cuts, lo, lo, hi);\n                push_cut(cuts, hi, lo, hi);\n                ld z1 = (ld)B + (ld)rs[j] / (ld)W;\n                ld z2 = (ld)T - (ld)rs[i] / (ld)W;\n                push_cut(cuts, (int)floor(z1 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z1 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z1), lo, hi);\n                push_cut(cuts, (int)floor(z2 + 1e-12L), lo, hi);\n                push_cut(cuts, (int)ceil(z2 - 1e-12L), lo, hi);\n                push_cut(cuts, (int)llround(z2), lo, hi);\n                if (b0.t == a0.b) push_cut(cuts, b0.t, lo, hi);\n                sort(cuts.begin(), cuts.end());\n                cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n                for (int c : cuts) {\n                    consider(Rect{L, c, R, T}, Rect{L, B, R, c});\n                }\n            }\n        }\n\n        const ld EPS = 1e-18L;\n        if (best_sat > cur_sat + EPS || (allow_equal && fabsl(best_sat - cur_sat) <= EPS && best_sec + 1e-15L < cur_sec)) {\n            res.valid = true;\n            res.i = i;\n            res.j = j;\n            res.ri = best_i;\n            res.rj = best_j;\n            res.gain = best_sat - cur_sat;\n            res.sec = best_sec;\n        }\n        return res;\n    }\n\n    bool rebuild_pass(vector<Rect>& rects, int K, bool allow_equal) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        K = min(K, n);\n        partial_sort(ord.begin(), ord.begin() + K, ord.end(), [&](int a, int b) {\n            ld da = 1.0L - satisfaction((ld)rs[a], (ld)rects[a].area());\n            ld db = 1.0L - satisfaction((ld)rs[b], (ld)rects[b].area());\n            if (fabsl(da - db) > 1e-18L) return da > db;\n            return rs[a] > rs[b];\n        });\n\n        bool any = false;\n        for (int z = 0; z < K; ++z) {\n            int i = ord[z];\n            auto [ok, nr] = best_rebuild_candidate(i, rects, allow_equal);\n            if (ok) {\n                rects[i] = nr;\n                any = true;\n            }\n        }\n        return any;\n    }\n\n    bool pair_rebuild_pass(vector<Rect>& rects, int K, bool allow_equal) {\n        K = min(K, n);\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        partial_sort(ord.begin(), ord.begin() + K, ord.end(), [&](int a, int b) {\n            ld da = 1.0L - satisfaction((ld)rs[a], (ld)rects[a].area());\n            ld db = 1.0L - satisfaction((ld)rs[b], (ld)rects[b].area());\n            if (fabsl(da - db) > 1e-18L) return da > db;\n            return rs[a] > rs[b];\n        });\n\n        vector<char> bad(n, 0);\n        for (int z = 0; z < K; ++z) bad[ord[z]] = 1;\n\n        PairCand best;\n        for (int z = 0; z < K; ++z) {\n            int i = ord[z];\n            for (int j = 0; j < n; ++j) if (j != i) {\n                if (bad[j] && j < i) continue;\n                PairCand cand = best_pair_rebuild_candidate(i, j, rects, allow_equal);\n                if (better_pair(cand, best)) best = cand;\n            }\n        }\n\n        if (best.valid) {\n            rects[best.i] = best.ri;\n            rects[best.j] = best.rj;\n            return true;\n        }\n        return false;\n    }\n\n    ld optimize(vector<Rect>& rects, const Params& params) {\n        long long occ = occupied_area(rects);\n\n        if (occ > 95000000LL) {\n            for (int rep = 0; rep < 2; ++rep) {\n                bool any = false;\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n                if (!any) break;\n            }\n        }\n\n        for (int pass = 0; pass < (int)params.caps.size(); ++pass) {\n            ld cap = params.caps[pass];\n            bool aggressive = (cap > 1e20L);\n            int mode = aggressive ? ((pass & 1) ? 5 : 2) : params.order_mode;\n            vector<int> ord = build_order(rects, mode, params.reverse_axis);\n\n            bool any = false;\n            for (int idx : ord) {\n                Move mv = best_move_for_rect(idx, rects, cap, aggressive,\n                                             params.action_prio, MASK_ALL);\n                if (mv.valid) {\n                    apply_move(rects[idx], mv.action, mv.delta);\n                    any = true;\n                }\n            }\n            if (!any && aggressive) break;\n        }\n\n        for (int rep = 0; rep < 2; ++rep) {\n            bool any = false;\n\n            {\n                vector<int> ord = build_order(rects, 6, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_SHR);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 5, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_EXP);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n            {\n                vector<int> ord = build_order(rects, 2, false);\n                for (int idx : ord) {\n                    Move mv = best_move_for_rect(idx, rects, INF_CAP, true,\n                                                 params.action_prio, MASK_ALL);\n                    if (mv.valid) {\n                        apply_move(rects[idx], mv.action, mv.delta);\n                        any = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return total_score(rects);\n    }\n\n    ld elapsed_sec() const {\n        return chrono::duration<ld>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    static bool same_rects(const vector<Rect>& a, const vector<Rect>& b) {\n        if (a.size() != b.size()) return false;\n        for (size_t i = 0; i < a.size(); ++i) {\n            if (a[i].l != b[i].l || a[i].b != b[i].b || a[i].r != b[i].r || a[i].t != b[i].t) return false;\n        }\n        return true;\n    }\n\n    bool update_elites(const vector<Rect>& cur, ld sc, ld sec,\n                       vector<Rect>& best_rects, ld& best_score, ld& best_sec,\n                       vector<Rect>& second_rects, ld& second_score, ld& second_sec) {\n        bool changed = false;\n\n        bool same_best = same_rects(cur, best_rects);\n        bool same_second = same_rects(cur, second_rects);\n\n        if (same_best) {\n            if (better_solution(sc, sec, best_score, best_sec)) {\n                best_score = sc;\n                best_sec = sec;\n                best_rects = cur;\n                changed = true;\n            }\n            return changed;\n        }\n\n        if (better_solution(sc, sec, best_score, best_sec)) {\n            if (!same_rects(best_rects, second_rects) &&\n                better_solution(best_score, best_sec, second_score, second_sec)) {\n                second_score = best_score;\n                second_sec = best_sec;\n                second_rects = best_rects;\n            }\n            best_score = sc;\n            best_sec = sec;\n            best_rects = cur;\n            changed = true;\n            return changed;\n        }\n\n        if (same_second) {\n            if (better_solution(sc, sec, second_score, second_sec)) {\n                second_score = sc;\n                second_sec = sec;\n                second_rects = cur;\n                changed = true;\n            }\n            return changed;\n        }\n\n        if (better_solution(sc, sec, second_score, second_sec)) {\n            second_score = sc;\n            second_sec = sec;\n            second_rects = cur;\n            changed = true;\n        }\n        return changed;\n    }\n\n    bool intensify_candidate(vector<Rect>& cand, ld& cand_score, ld& cand_sec,\n                             int pairK, int singleK) {\n        bool any = false;\n        any |= pair_rebuild_pass(cand, min(pairK, n), true);\n        any |= rebuild_pass(cand, min(singleK, n), true);\n        if (!any) return false;\n        cand_score = optimize(cand, polish_params());\n        cand_sec = total_secondary(cand);\n        return true;\n    }\n\n    bool final_polish_once(vector<Rect>& cand, ld& cand_score, ld& cand_sec,\n                           int pairK, int singleK) {\n        bool any = false;\n        any |= pair_rebuild_pass(cand, min(pairK, n), true);\n        if (elapsed_sec() >= 4.93L) return any;\n        any |= pair_rebuild_pass(cand, min(pairK, n), true);\n        if (elapsed_sec() >= 4.93L) return any;\n        any |= rebuild_pass(cand, min(singleK, n), true);\n        if (!any) return false;\n        cand_score = optimize(cand, polish_params());\n        cand_sec = total_secondary(cand);\n        return true;\n    }\n\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        xs.resize(n);\n        ys.resize(n);\n        rs.resize(n);\n        sqrs.resize(n);\n\n        uint64_t seed = 1469598103934665603ULL;\n        for (int i = 0; i < n; ++i) {\n            cin >> xs[i] >> ys[i] >> rs[i];\n            sqrs[i] = sqrt((ld)rs[i]);\n            seed ^= (uint64_t)(xs[i] + 1) * 1000003ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(ys[i] + 7) * 1000033ULL;\n            seed *= 1099511628211ULL;\n            seed ^= (uint64_t)(rs[i] + 13) * 1000037ULL;\n            seed *= 1099511628211ULL;\n        }\n        rng = XorShift64(seed);\n\n        nearest_idx.assign(n, -1);\n        for (int i = 0; i < n; ++i) {\n            long long bestd = (1LL << 62);\n            for (int j = 0; j < n; ++j) if (i != j) {\n                long long dx = xs[i] - xs[j];\n                long long dy = ys[i] - ys[j];\n                long long d = dx * dx + dy * dy;\n                if (d < bestd) {\n                    bestd = d;\n                    nearest_idx[i] = j;\n                }\n            }\n        }\n\n        start_time = chrono::steady_clock::now();\n\n        vector<Rect> best_rects = initial_rects();\n        ld best_score = total_score(best_rects);\n        ld best_sec = total_secondary(best_rects);\n\n        vector<Rect> second_rects = best_rects;\n        ld second_score = -1e100L;\n        ld second_sec = INF_CAP;\n\n        for (int t = 0; t < 2 && elapsed_sec() < 1.35L; ++t) {\n            vector<Rect> cur = initial_rects();\n            Params p = random_constructive_params();\n            ld sc = optimize(cur, p);\n            ld sec = total_secondary(cur);\n            update_elites(cur, sc, sec, best_rects, best_score, best_sec,\n                          second_rects, second_score, second_sec);\n        }\n\n        for (int t = 0; t < 4 && elapsed_sec() < 2.30L; ++t) {\n            vector<Rect> cur = build_partition_solution(random_bsp_params());\n            Params p = random_partition_params();\n            ld sc = optimize(cur, p);\n            ld sec = total_secondary(cur);\n            update_elites(cur, sc, sec, best_rects, best_score, best_sec,\n                          second_rects, second_score, second_sec);\n        }\n\n        int iter = 0;\n        while (elapsed_sec() < 4.54L) {\n            ld old_best_score = best_score;\n            ld old_best_sec = best_sec;\n\n            vector<Rect> cur;\n            Params p;\n\n            if (iter < 6) {\n                if (iter & 1) {\n                    cur = build_partition_solution(random_bsp_params());\n                    p = random_partition_params();\n                } else {\n                    cur = initial_rects();\n                    p = random_constructive_params();\n                }\n            } else {\n                ld u = rng.uniform();\n                if (u < 0.18L) {\n                    cur = initial_rects();\n                    p = random_constructive_params();\n                } else if (u < 0.42L) {\n                    cur = build_partition_solution(random_bsp_params());\n                    p = random_partition_params();\n                } else {\n                    const vector<Rect>& base =\n                        (second_score > -1e90L && rng.next_int(100) < 25) ? second_rects : best_rects;\n                    cur = perturb_from_best(base);\n                    p = random_perturb_params();\n                }\n            }\n\n            ld sc = optimize(cur, p);\n            ld sec = total_secondary(cur);\n            bool best_changed_before = better_solution(best_score, best_sec, old_best_score, old_best_sec);\n\n            update_elites(cur, sc, sec, best_rects, best_score, best_sec,\n                          second_rects, second_score, second_sec);\n\n            bool best_changed_after = better_solution(best_score, best_sec, old_best_score, old_best_sec);\n\n            if (best_changed_after) {\n                if (elapsed_sec() < 4.26L) {\n                    vector<Rect> tmp = best_rects;\n                    ld sc2 = best_score, sec2 = best_sec;\n                    if (intensify_candidate(tmp, sc2, sec2, 12, 8)) {\n                        update_elites(tmp, sc2, sec2, best_rects, best_score, best_sec,\n                                      second_rects, second_score, second_sec);\n                    }\n                }\n            } else {\n                if ((iter % 6 == 0) && elapsed_sec() < 4.18L && sc + 0.015L >= old_best_score) {\n                    vector<Rect> tmp = cur;\n                    ld sc2 = sc, sec2 = sec;\n                    if (intensify_candidate(tmp, sc2, sec2, 10, 6)) {\n                        update_elites(tmp, sc2, sec2, best_rects, best_score, best_sec,\n                                      second_rects, second_score, second_sec);\n                    }\n                }\n            }\n\n            (void)best_changed_before;\n            ++iter;\n        }\n\n        while (elapsed_sec() < 4.93L) {\n            bool any_elite_changed = false;\n\n            {\n                vector<Rect> tmp = best_rects;\n                ld sc = best_score, sec = best_sec;\n                if (final_polish_once(tmp, sc, sec, 14, 10)) {\n                    any_elite_changed |= update_elites(tmp, sc, sec, best_rects, best_score, best_sec,\n                                                       second_rects, second_score, second_sec);\n                }\n            }\n\n            if (elapsed_sec() < 4.93L &&\n                second_score > -1e90L &&\n                !same_rects(best_rects, second_rects) &&\n                second_score + 0.03L >= best_score) {\n                vector<Rect> tmp = second_rects;\n                ld sc = second_score, sec = second_sec;\n                if (final_polish_once(tmp, sc, sec, 12, 8)) {\n                    any_elite_changed |= update_elites(tmp, sc, sec, best_rects, best_score, best_sec,\n                                                       second_rects, second_score, second_sec);\n                }\n            }\n\n            if (!any_elite_changed) break;\n        }\n\n        for (int i = 0; i < n; ++i) {\n            cout << best_rects[i].l << ' ' << best_rects[i].b << ' '\n                 << best_rects[i].r << ' ' << best_rects[i].t << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc002":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 50;\nstatic constexpr int W = 50;\nstatic constexpr int V = H * W;\n\nusing Clock = chrono::steady_clock;\n\nstruct XorShift64 {\n    uint64_t x = 88172645463325252ull;\n    void seed(uint64_t s) { x = s ? s : 88172645463325252ull; }\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next_u64() % (uint64_t)(r - l + 1));\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\ninline int id(int i, int j) { return i * W + j; }\n\nstruct CompStat {\n    int tiles;\n    int ub;\n};\n\nstruct Params {\n    int lookDepth = 6;\n    int tilesMargin = 0;\n    int ubMargin = 0;\n    int lookMargin = 0;\n    bool deterministic = false;\n    int style = 0; // 0: safe/length-biased, 1: score-biased\n};\n\nstruct Path {\n    vector<int> pos;\n    vector<int> prefixScore;\n    vector<unsigned char> branchCnt;\n    vector<int> branchPoints;\n    int score = 0;\n};\n\nstruct MoveInfo {\n    int v = -1;\n    int addScore = 0;\n    int addLen = 0;\n    int reachTiles = 0;\n    int reachUb = 0;\n    int deg = 0;\n    int look = INT_MIN;\n\n    // weak branch-richness features at corridor endpoint\n    int altTiles = 0;\n    int altUb = 0;\n};\n\nint si, sj, startIdx;\nint tileId[V];\nint pval[V];\nint M;\n\nint adjList[V][4];\nunsigned char adjCnt[V];\n\nvector<int> tileMaxVal;\nvector<unsigned char> usedTile;\nvector<unsigned char> tmpUsed;\n\nint visSq[V];\nvector<int> visTile;\nint bfsStamp = 1;\nint tileStamp = 1;\nint qbuf[V];\n\nClock::time_point globalDeadline;\n\n// opening search\nvector<int> openingCur, openingBest;\nlong long openingBestUB = -1;\nint openingBestTiles = -1;\nint openingBestAcc = -1;\nClock::time_point openingDeadline;\nbool openingTimeout = false;\nint openingNodes = 0;\nstatic constexpr int OPENING_NODE_LIMIT = 13000;\n\ninline int avail_neighbors(int u, int out[4]) {\n    int c = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) out[c++] = v;\n    }\n    return c;\n}\n\ninline CompStat component_stat(int s) {\n    const int st = tileId[s];\n    ++bfsStamp;\n    ++tileStamp;\n\n    int head = 0, tail = 0;\n    qbuf[tail++] = s;\n    visSq[s] = bfsStamp;\n    visTile[st] = tileStamp;\n\n    int tiles = 1;\n    int ub = pval[s];\n\n    while (head < tail) {\n        int u = qbuf[head++];\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            int tv = tileId[v];\n            if (tv == st || usedTile[tv]) continue;\n            if (visSq[v] != bfsStamp) {\n                visSq[v] = bfsStamp;\n                qbuf[tail++] = v;\n            }\n            if (visTile[tv] != tileStamp) {\n                visTile[tv] = tileStamp;\n                ++tiles;\n                ub += tileMaxVal[tv];\n            }\n        }\n    }\n    return {tiles, ub};\n}\n\ninline void best_future_from_current(int u, int& bestTiles, int& bestUb) {\n    bestTiles = 0;\n    bestUb = 0;\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        if (!usedTile[tileId[v]]) {\n            auto cs = component_stat(v);\n            if (cs.tiles > bestTiles) bestTiles = cs.tiles;\n            if (cs.ub > bestUb) bestUb = cs.ub;\n        }\n    }\n}\n\nint local_dfs(int u, int depth) {\n    int trail[16];\n    int tcnt = 0;\n    int gain = 0;\n\n    while (depth > 0) {\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n        if (ccnt == 0) {\n            for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n            return gain;\n        }\n        if (ccnt == 1) {\n            int v = cand[0];\n            int tv = tileId[v];\n            usedTile[tv] = 1;\n            trail[tcnt++] = tv;\n            gain += pval[v];\n            u = v;\n            --depth;\n            continue;\n        }\n        break;\n    }\n\n    if (depth == 0) {\n        for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n        return gain;\n    }\n\n    struct Cand {\n        int v;\n        int pri;\n    };\n    Cand cand2[4];\n    int n2 = 0;\n\n    for (int k = 0; k < adjCnt[u]; ++k) {\n        int v = adjList[u][k];\n        int tv = tileId[v];\n        if (usedTile[tv]) continue;\n        usedTile[tv] = 1;\n        int out[4];\n        int deg = avail_neighbors(v, out);\n        usedTile[tv] = 0;\n        cand2[n2++] = {v, pval[v] * 8 + deg * 5};\n    }\n\n    sort(cand2, cand2 + n2, [](const Cand& a, const Cand& b) {\n        return a.pri > b.pri;\n    });\n\n    int best = 0;\n    for (int i = 0; i < n2; ++i) {\n        int v = cand2[i].v;\n        int tv = tileId[v];\n        usedTile[tv] = 1;\n        int sc = pval[v] + local_dfs(v, depth - 1);\n        usedTile[tv] = 0;\n        if (sc > best) best = sc;\n    }\n\n    for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n    return gain + best;\n}\n\nvoid preview_move_corridor(int v, MoveInfo& info) {\n    info = MoveInfo();\n    info.v = v;\n\n    int trail[V];\n    int tcnt = 0;\n    int cur = v;\n    int addScore = 0;\n    int addLen = 0;\n\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        trail[tcnt++] = tv;\n        addScore += pval[cur];\n        ++addLen;\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) {\n            int bestTiles1 = 0, bestTiles2 = 0;\n            int bestUb1 = 0, bestUb2 = 0;\n\n            for (int i = 0; i < ccnt; ++i) {\n                auto cs = component_stat(cand[i]);\n                if (cs.tiles > bestTiles1 || (cs.tiles == bestTiles1 && cs.ub > bestUb1)) {\n                    bestTiles2 = bestTiles1;\n                    bestUb2 = bestUb1;\n                    bestTiles1 = cs.tiles;\n                    bestUb1 = cs.ub;\n                } else if (cs.tiles > bestTiles2 || (cs.tiles == bestTiles2 && cs.ub > bestUb2)) {\n                    bestTiles2 = cs.tiles;\n                    bestUb2 = cs.ub;\n                }\n            }\n\n            info.addScore = addScore;\n            info.addLen = addLen;\n            info.deg = ccnt;\n            info.reachTiles = addLen + bestTiles1;\n            info.reachUb = addScore + bestUb1;\n            info.altTiles = bestTiles2;\n            info.altUb = bestUb2;\n            break;\n        }\n        cur = cand[0];\n    }\n\n    for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n}\n\nint look_move_corridor(int v, int totalDepth) {\n    int trail[V];\n    int tcnt = 0;\n    int cur = v;\n    int addScore = 0;\n    int addLen = 0;\n\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        trail[tcnt++] = tv;\n        addScore += pval[cur];\n        ++addLen;\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) {\n            int rem = max(0, totalDepth - addLen);\n            int res = addScore + local_dfs(cur, rem);\n            for (int i = 0; i < tcnt; ++i) usedTile[trail[i]] = 0;\n            return res;\n        }\n        cur = cand[0];\n    }\n}\n\nvoid commit_corridor(Path& res, int v) {\n    int cur = v;\n    while (true) {\n        int tv = tileId[cur];\n        usedTile[tv] = 1;\n        res.pos.push_back(cur);\n        res.score += pval[cur];\n\n        int cand[4];\n        int ccnt = avail_neighbors(cur, cand);\n        if (ccnt != 1) break;\n        cur = cand[0];\n    }\n}\n\nbool better_move(const MoveInfo& a, const MoveInfo& b, int step, const Params& prm) {\n    if (prm.style == 0) {\n        if (prm.deterministic || step < 80) {\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.altUb != b.altUb) return a.altUb > b.altUb;\n            if (a.look != b.look) return a.look > b.look;\n        } else if (step < 250) {\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n        } else {\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n        }\n    } else {\n        if (prm.deterministic || step < 80) {\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altUb != b.altUb) return a.altUb > b.altUb;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n        } else if (step < 250) {\n            if (a.look != b.look) return a.look > b.look;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.altUb != b.altUb) return a.altUb > b.altUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n        } else {\n            if (a.look != b.look) return a.look > b.look;\n            if (a.addScore != b.addScore) return a.addScore > b.addScore;\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n        }\n    }\n    if (a.addScore != b.addScore) return a.addScore > b.addScore;\n    if (a.deg != b.deg) return a.deg > b.deg;\n    return pval[a.v] > pval[b.v];\n}\n\nPath build_path(vector<int> pos, int score, const Params& prm, const Clock::time_point& deadline) {\n    Path res;\n    res.pos = std::move(pos);\n    res.score = score;\n    res.pos.reserve(V);\n\n    int it = 0;\n    while (true) {\n        if ((it++ & 31) == 0) {\n            if (Clock::now() >= deadline) break;\n        }\n\n        int u = res.pos.back();\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n        if (ccnt == 0) break;\n\n        if (ccnt == 1) {\n            commit_corridor(res, cand[0]);\n            continue;\n        }\n\n        MoveInfo info[4];\n        for (int i = 0; i < ccnt; ++i) preview_move_corridor(cand[i], info[i]);\n\n        int step = (int)res.pos.size();\n\n        int baseTM, baseUM, baseLM;\n        if (prm.deterministic || step < 60) {\n            baseTM = 0; baseUM = 40; baseLM = 4;\n        } else if (step < 180) {\n            baseTM = 1; baseUM = 120; baseLM = 8;\n        } else if (step < 400) {\n            baseTM = 2; baseUM = 220; baseLM = 12;\n        } else {\n            baseTM = 4; baseUM = 450; baseLM = 18;\n        }\n\n        if (prm.style == 1) {\n            baseTM += 1;\n            baseUM = max(0, baseUM - 35);\n            baseLM = max(2, baseLM - 1);\n        }\n\n        int tm = baseTM + prm.tilesMargin;\n        int um = baseUM + prm.ubMargin;\n        int lm = baseLM + prm.lookMargin;\n\n        int lookDepth = prm.lookDepth + (step < 30 ? 2 : step < 90 ? 1 : 0);\n        if (prm.deterministic) ++lookDepth;\n        lookDepth = min(lookDepth, 9);\n\n        int chosen = info[0].v;\n\n        if (prm.deterministic || step < 26) {\n            for (int i = 0; i < ccnt; ++i) info[i].look = look_move_corridor(info[i].v, lookDepth);\n            int bestIdx = 0;\n            for (int i = 1; i < ccnt; ++i) {\n                if (better_move(info[i], info[bestIdx], step, prm)) bestIdx = i;\n            }\n            chosen = info[bestIdx].v;\n        } else {\n            int alive[4];\n            int acnt = ccnt;\n            for (int i = 0; i < ccnt; ++i) alive[i] = i;\n\n            int bestTiles = -1;\n            for (int i = 0; i < acnt; ++i) bestTiles = max(bestTiles, info[alive[i]].reachTiles);\n            {\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].reachTiles >= bestTiles - tm) nxt[ncnt++] = idx;\n                }\n                for (int i = 0; i < ncnt; ++i) alive[i] = nxt[i];\n                acnt = ncnt;\n            }\n\n            int bestUb = -1;\n            for (int i = 0; i < acnt; ++i) bestUb = max(bestUb, info[alive[i]].reachUb);\n            {\n                int nxt[4], ncnt = 0;\n                for (int i = 0; i < acnt; ++i) {\n                    int idx = alive[i];\n                    if (info[idx].reachUb >= bestUb - um) nxt[ncnt++] = idx;\n                }\n                for (int i = 0; i < ncnt; ++i) alive[i] = nxt[i];\n                acnt = ncnt;\n            }\n\n            for (int i = 0; i < acnt; ++i) {\n                int idx = alive[i];\n                info[idx].look = look_move_corridor(info[idx].v, lookDepth);\n            }\n\n            int bestLook = INT_MIN;\n            for (int i = 0; i < acnt; ++i) bestLook = max(bestLook, info[alive[i]].look);\n\n            int fin[4], fcnt = 0;\n            int w[4], wsum = 0;\n            for (int i = 0; i < acnt; ++i) {\n                int idx = alive[i];\n                if (info[idx].look >= bestLook - lm) {\n                    fin[fcnt] = idx;\n                    int ww = info[idx].look - (bestLook - lm) + 1;\n                    ww += info[idx].deg * 2;\n                    ww += info[idx].addScore / (prm.style == 1 ? 8 : 12);\n                    ww += min(6, info[idx].altTiles / 35);\n                    if (prm.style == 1) ww += min(6, info[idx].altUb / 250);\n                    if (ww < 1) ww = 1;\n                    w[fcnt] = ww;\n                    wsum += ww;\n                    ++fcnt;\n                }\n            }\n\n            int r = rng.next_int(1, wsum);\n            chosen = info[fin[0]].v;\n            for (int i = 0; i < fcnt; ++i) {\n                r -= w[i];\n                if (r <= 0) {\n                    chosen = info[fin[i]].v;\n                    break;\n                }\n            }\n        }\n\n        commit_corridor(res, chosen);\n    }\n\n    return res;\n}\n\nvoid prepare_path(Path& path) {\n    int n = (int)path.pos.size();\n    path.prefixScore.assign(n, 0);\n    path.branchCnt.assign(n, 0);\n    path.branchPoints.clear();\n\n    fill(tmpUsed.begin(), tmpUsed.end(), 0);\n    int s = 0;\n    for (int i = 0; i < n; ++i) {\n        int u = path.pos[i];\n        tmpUsed[tileId[u]] = 1;\n        s += pval[u];\n        path.prefixScore[i] = s;\n\n        int cnt = 0;\n        for (int k = 0; k < adjCnt[u]; ++k) {\n            int v = adjList[u][k];\n            if (!tmpUsed[tileId[v]]) ++cnt;\n        }\n        path.branchCnt[i] = (unsigned char)cnt;\n        if (cnt >= 2) path.branchPoints.push_back(i);\n    }\n    path.score = s;\n}\n\nbool better_path(const Path& a, const Path& b) {\n    if (a.score != b.score) return a.score > b.score;\n    return a.pos.size() > b.pos.size();\n}\n\nvoid add_elite(vector<Path>& elites, Path cand, int keep = 7) {\n    prepare_path(cand);\n    elites.push_back(std::move(cand));\n    sort(elites.begin(), elites.end(), [](const Path& a, const Path& b) {\n        return better_path(a, b);\n    });\n    if ((int)elites.size() > keep) elites.resize(keep);\n}\n\nint choose_elite(const vector<Path>& elites) {\n    int n = (int)elites.size();\n    int sum = 0;\n    for (int i = 0; i < n; ++i) sum += (n - i);\n    int r = rng.next_int(1, sum);\n    for (int i = 0; i < n; ++i) {\n        r -= (n - i);\n        if (r <= 0) return i;\n    }\n    return 0;\n}\n\nint choose_cut(const Path& path) {\n    if (path.branchPoints.empty()) return 0;\n    const auto& bp = path.branchPoints;\n    int n = (int)bp.size();\n\n    int l = 0, r = n - 1;\n    if (n >= 3) {\n        int a = n / 3;\n        int b = (2 * n) / 3;\n        double x = rng.next_double();\n        if (x < 0.20) {\n            l = 0; r = max(0, a - 1);\n        } else if (x < 0.60) {\n            l = a; r = max(a, b - 1);\n        } else {\n            l = b; r = n - 1;\n        }\n    }\n    return bp[l + rng.next_int(0, r - l)];\n}\n\n// opening search\nvoid consider_open_leaf(int u, int accScore) {\n    int bt, bu;\n    best_future_from_current(u, bt, bu);\n    long long totalUB = (long long)accScore + bu;\n    int totalTiles = (int)openingCur.size() + bt;\n    if (totalUB > openingBestUB ||\n        (totalUB == openingBestUB && (totalTiles > openingBestTiles ||\n         (totalTiles == openingBestTiles && accScore > openingBestAcc)))) {\n        openingBestUB = totalUB;\n        openingBestTiles = totalTiles;\n        openingBestAcc = accScore;\n        openingBest = openingCur;\n    }\n}\n\nvoid opening_dfs(int u, int depthChoices, int accScore) {\n    if (openingTimeout) return;\n    if ((++openingNodes & 511) == 0) {\n        if (openingNodes >= OPENING_NODE_LIMIT || Clock::now() >= openingDeadline) {\n            openingTimeout = true;\n            return;\n        }\n    }\n\n    while (true) {\n        int cand[4];\n        int ccnt = avail_neighbors(u, cand);\n\n        if (ccnt == 0) {\n            consider_open_leaf(u, accScore);\n            return;\n        }\n\n        if (ccnt == 1) {\n            int v = cand[0];\n            usedTile[tileId[v]] = 1;\n            openingCur.push_back(v);\n            accScore += pval[v];\n            u = v;\n            continue;\n        }\n\n        int bt, bu;\n        best_future_from_current(u, bt, bu);\n        long long ubTotal = (long long)accScore + bu;\n        int tilesTotal = (int)openingCur.size() + bt;\n        if (ubTotal < openingBestUB ||\n            (ubTotal == openingBestUB && tilesTotal <= openingBestTiles)) {\n            return;\n        }\n\n        if (depthChoices == 0) {\n            consider_open_leaf(u, accScore);\n            return;\n        }\n\n        struct Ord {\n            int v, reachUb, reachTiles, altTiles, addScore;\n        };\n        Ord ord[4];\n        for (int i = 0; i < ccnt; ++i) {\n            MoveInfo mi;\n            preview_move_corridor(cand[i], mi);\n            ord[i] = {cand[i], mi.reachUb, mi.reachTiles, mi.altTiles, mi.addScore};\n        }\n\n        sort(ord, ord + ccnt, [](const Ord& a, const Ord& b) {\n            if (a.reachUb != b.reachUb) return a.reachUb > b.reachUb;\n            if (a.reachTiles != b.reachTiles) return a.reachTiles > b.reachTiles;\n            if (a.altTiles != b.altTiles) return a.altTiles > b.altTiles;\n            return a.addScore > b.addScore;\n        });\n\n        for (int i = 0; i < ccnt; ++i) {\n            int trail[V];\n            int tcnt = 0;\n            int cur = ord[i].v;\n            int add = 0;\n\n            while (true) {\n                int tv = tileId[cur];\n                usedTile[tv] = 1;\n                trail[tcnt++] = cur;\n                openingCur.push_back(cur);\n                add += pval[cur];\n\n                int nexts[4];\n                int nc = avail_neighbors(cur, nexts);\n                if (nc != 1) break;\n                cur = nexts[0];\n            }\n\n            opening_dfs(cur, depthChoices - 1, accScore + add);\n\n            for (int j = 0; j < tcnt; ++j) usedTile[tileId[trail[j]]] = 0;\n            for (int j = 0; j < tcnt; ++j) openingCur.pop_back();\n\n            if (openingTimeout) return;\n        }\n        return;\n    }\n}\n\nstring to_answer(const vector<int>& pos) {\n    string ans;\n    ans.reserve(pos.size() > 0 ? pos.size() - 1 : 0);\n    for (size_t i = 1; i < pos.size(); ++i) {\n        int d = pos[i] - pos[i - 1];\n        if (d == -W) ans.push_back('U');\n        else if (d == W) ans.push_back('D');\n        else if (d == -1) ans.push_back('L');\n        else if (d == 1) ans.push_back('R');\n    }\n    return ans;\n}\n\nParams random_params(int mode) {\n    Params p;\n    if (mode == 2) { // elite suffix\n        p.style = (rng.next_double() < 0.28 ? 1 : 0);\n        if (p.style == 0) {\n            p.lookDepth = 5 + rng.next_int(0, 1);\n            p.tilesMargin = rng.next_int(0, 2);\n            p.ubMargin = rng.next_int(0, 90);\n            p.lookMargin = rng.next_int(0, 8);\n        } else {\n            p.lookDepth = 5 + rng.next_int(0, 1);\n            p.tilesMargin = 1 + rng.next_int(0, 2);\n            p.ubMargin = rng.next_int(0, 70);\n            p.lookMargin = rng.next_int(0, 7);\n        }\n    } else { // restart / opening prefix\n        p.style = (rng.next_double() < 0.35 ? 1 : 0);\n        if (p.style == 0) {\n            p.lookDepth = 6 + rng.next_int(0, 1);\n            p.tilesMargin = rng.next_int(0, 1);\n            p.ubMargin = rng.next_int(0, 70);\n            p.lookMargin = rng.next_int(0, 6);\n        } else {\n            p.lookDepth = 6 + rng.next_int(0, 1);\n            p.tilesMargin = 1 + rng.next_int(0, 1);\n            p.ubMargin = rng.next_int(0, 55);\n            p.lookMargin = rng.next_int(0, 5);\n        }\n    }\n    p.deterministic = false;\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si >> sj;\n    startIdx = id(si, sj);\n\n    int maxTile = -1;\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int t;\n            cin >> t;\n            tileId[id(i, j)] = t;\n            maxTile = max(maxTile, t);\n        }\n    }\n    M = maxTile + 1;\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            cin >> pval[id(i, j)];\n        }\n    }\n\n    tileMaxVal.assign(M, 0);\n    for (int v = 0; v < V; ++v) {\n        tileMaxVal[tileId[v]] = max(tileMaxVal[tileId[v]], pval[v]);\n    }\n\n    for (int i = 0; i < H; ++i) {\n        for (int j = 0; j < W; ++j) {\n            int u = id(i, j);\n            int cnt = 0;\n            static const int di[4] = {-1, 1, 0, 0};\n            static const int dj[4] = {0, 0, -1, 1};\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 >= H || nj < 0 || nj >= W) continue;\n                int v = id(ni, nj);\n                if (tileId[v] == tileId[u]) continue;\n                adjList[u][cnt++] = v;\n            }\n            adjCnt[u] = (unsigned char)cnt;\n        }\n    }\n\n    usedTile.assign(M, 0);\n    tmpUsed.assign(M, 0);\n    visTile.assign(M, 0);\n    memset(visSq, 0, sizeof(visSq));\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)startIdx + 0x9e3779b97f4a7c15ull;\n    for (int v = 0; v < V; ++v) {\n        seed = seed * 1000003ull ^ (uint64_t)(tileId[v] + 1);\n        seed = seed * 1000003ull ^ (uint64_t)(pval[v] + 7);\n    }\n    rng.seed(seed);\n\n    globalDeadline = Clock::now() + chrono::milliseconds(1835);\n\n    // opening search\n    fill(usedTile.begin(), usedTile.end(), 0);\n    usedTile[tileId[startIdx]] = 1;\n\n    openingCur.clear();\n    openingBest.clear();\n    openingBestUB = -1;\n    openingBestTiles = -1;\n    openingBestAcc = -1;\n    openingTimeout = false;\n    openingNodes = 0;\n    openingDeadline = min(globalDeadline, Clock::now() + chrono::milliseconds(110));\n\n    opening_dfs(startIdx, 7, pval[startIdx]);\n\n    vector<int> openingPrefix;\n    openingPrefix.push_back(startIdx);\n    for (int v : openingBest) openingPrefix.push_back(v);\n\n    vector<Path> elites;\n\n    // baseline 1: opening prefix + deterministic safe\n    {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        int score = 0;\n        for (int v : openingPrefix) {\n            usedTile[tileId[v]] = 1;\n            score += pval[v];\n        }\n        Params safe;\n        safe.lookDepth = 7;\n        safe.tilesMargin = 0;\n        safe.ubMargin = 0;\n        safe.lookMargin = 0;\n        safe.deterministic = true;\n        safe.style = 0;\n        Path base = build_path(openingPrefix, score, safe, globalDeadline);\n        add_elite(elites, std::move(base));\n    }\n\n    // baseline 2: start only + deterministic safe\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        Params safe;\n        safe.lookDepth = 6;\n        safe.deterministic = true;\n        safe.style = 0;\n        Path base2 = build_path(vector<int>{startIdx}, pval[startIdx], safe, globalDeadline);\n        add_elite(elites, std::move(base2));\n    }\n\n    // baseline 3: start only + deterministic score-biased\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        Params agg;\n        agg.lookDepth = 6;\n        agg.tilesMargin = 1;\n        agg.ubMargin = 0;\n        agg.lookMargin = 0;\n        agg.deterministic = true;\n        agg.style = 1;\n        Path base3 = build_path(vector<int>{startIdx}, pval[startIdx], agg, globalDeadline);\n        add_elite(elites, std::move(base3));\n    }\n\n    // baseline 4: opening prefix + randomized\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        int score = 0;\n        for (int v : openingPrefix) {\n            usedTile[tileId[v]] = 1;\n            score += pval[v];\n        }\n        Params rp = random_params(1);\n        Path base4 = build_path(openingPrefix, score, rp, globalDeadline);\n        add_elite(elites, std::move(base4));\n    }\n\n    // baseline 5: start only + randomized\n    if (Clock::now() < globalDeadline) {\n        fill(usedTile.begin(), usedTile.end(), 0);\n        usedTile[tileId[startIdx]] = 1;\n        Params rp = random_params(0);\n        Path base5 = build_path(vector<int>{startIdx}, pval[startIdx], rp, globalDeadline);\n        add_elite(elites, std::move(base5));\n    }\n\n    while (Clock::now() < globalDeadline) {\n        int mode = 2; // 0:start, 1:opening prefix, 2:elite suffix\n        double x = rng.next_double();\n        if (elites.empty() || x < 0.26) mode = 0;\n        else if (x < 0.38 && openingPrefix.size() > 1) mode = 1;\n\n        fill(usedTile.begin(), usedTile.end(), 0);\n        vector<int> pref;\n        int score = 0;\n\n        if (mode == 0) {\n            pref = {startIdx};\n            usedTile[tileId[startIdx]] = 1;\n            score = pval[startIdx];\n        } else if (mode == 1) {\n            int n = (int)openingPrefix.size();\n            int len;\n            if (n <= 2) len = n;\n            else if (rng.next_double() < 0.50) len = n;\n            else len = rng.next_int(max(1, n / 2), n);\n            pref.assign(openingPrefix.begin(), openingPrefix.begin() + len);\n            for (int v : pref) {\n                usedTile[tileId[v]] = 1;\n                score += pval[v];\n            }\n        } else {\n            int ei = choose_elite(elites);\n            const Path& src = elites[ei];\n            if (src.branchPoints.empty()) {\n                pref = {startIdx};\n                usedTile[tileId[startIdx]] = 1;\n                score = pval[startIdx];\n            } else {\n                int cut = choose_cut(src);\n                pref.assign(src.pos.begin(), src.pos.begin() + cut + 1);\n                score = src.prefixScore[cut];\n                for (int i = 0; i <= cut; ++i) usedTile[tileId[src.pos[i]]] = 1;\n            }\n        }\n\n        Params prm = random_params(mode);\n        Path cand = build_path(std::move(pref), score, prm, globalDeadline);\n        add_elite(elites, std::move(cand));\n    }\n\n    if (elites.empty()) {\n        cout << '\\n';\n        return 0;\n    }\n\n    cout << to_answer(elites[0].pos) << '\\n';\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int HN = N * (N - 1);   // 870\nstatic constexpr int VN = (N - 1) * N;   // 870\nstatic constexpr int E = HN + VN;        // 1740\n\nstatic constexpr double INIT_COST = 5000.0;\nstatic constexpr double MIN_COST = 1000.0;\nstatic constexpr double MAX_COST = 9000.0;\n\ninline int hid(int i, int j) { return i * 29 + j; }\ninline int vid(int i, int j) { return HN + i * 30 + j; }\ninline int node_id(int i, int j) { return i * N + j; }\n\nstruct Path {\n    string s;\n    vector<int> edges;\n    double sumX = 0.0;\n    double sumPrior = 0.0;\n    double sumUnc = 0.0;\n    double sumGap = 0.0;\n};\n\nstruct Observation {\n    vector<int> edges;\n    array<uint8_t, 30> hcnt{};\n    array<uint8_t, 30> vcnt{};\n    double y = 0.0;\n    double w = 0.0;\n    int len = 0;\n};\n\nstruct FitRes29 {\n    array<double, 29> out{};\n    bool use_two = false;\n    double improve = 0.0;\n    double diff = 0.0;\n};\n\nstruct Solver {\n    vector<double> x;\n    vector<double> prior;\n    vector<int> vis;\n    vector<Observation> hist;\n\n    array<double, 30> rowAvgH{};\n    array<double, 30> colAvgV{};\n\n    mt19937 rng;\n\n    Solver() : x(E, INIT_COST), prior(E, INIT_COST), vis(E, 0) {\n        rng.seed((uint64_t)chrono::steady_clock::now().time_since_epoch().count());\n        for (int i = 0; i < 30; ++i) {\n            rowAvgH[i] = INIT_COST;\n            colAvgV[i] = INIT_COST;\n        }\n        hist.reserve(1000);\n    }\n\n    int randint(int l, int r) {\n        return uniform_int_distribution<int>(l, r)(rng);\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    static double clampd(double x, double lo, double hi) {\n        if (x < lo) return lo;\n        if (x > hi) return hi;\n        return x;\n    }\n\n    static double dot_vec(const vector<double>& a, const vector<double>& b) {\n        double s = 0.0;\n        for (int i = 0; i < (int)a.size(); ++i) s += a[i] * b[i];\n        return s;\n    }\n\n    inline double est_edge(int e) const {\n        return clampd(x[e], MIN_COST, MAX_COST);\n    }\n\n    inline double plan_edge(int e) const {\n        double conf = (double)vis[e] / ((double)vis[e] + 3.0);\n        return clampd((1.0 - conf) * prior[e] + conf * x[e], MIN_COST, MAX_COST);\n    }\n\n    inline double unc_edge(int e) const {\n        return 1.0 / sqrt((double)vis[e] + 1.0);\n    }\n\n    double stage_wx(int qidx) const {\n        if (qidx < 100) return 0.40;\n        if (qidx < 250) return 0.50;\n        if (qidx < 600) return 0.62;\n        return 0.74;\n    }\n\n    double stage_ucoef(int qidx) const {\n        if (qidx < 120) return 110.0;\n        if (qidx < 350) return 70.0;\n        return 35.0;\n    }\n\n    double stage_gcoef(int qidx) const {\n        if (qidx < 120) return 0.06;\n        if (qidx < 350) return 0.035;\n        return 0.015;\n    }\n\n    void finalize_path(Path& p) const {\n        p.sumX = p.sumPrior = p.sumUnc = p.sumGap = 0.0;\n        for (int e : p.edges) {\n            double xe = est_edge(e);\n            double pe = prior[e];\n            p.sumX += xe;\n            p.sumPrior += pe;\n            p.sumUnc += unc_edge(e);\n            p.sumGap += fabs(xe - pe);\n        }\n    }\n\n    FitRes29 fit_piecewise_29(const array<double, 29>& val, const array<double, 29>& wt) const {\n        FitRes29 res;\n\n        array<double, 30> W{}, S{}, Q{};\n        for (int i = 0; i < 29; ++i) {\n            W[i + 1] = W[i] + wt[i];\n            S[i + 1] = S[i] + wt[i] * val[i];\n            Q[i + 1] = Q[i] + wt[i] * val[i] * val[i];\n        }\n\n        auto seg = [&](int l, int r) -> tuple<double, double, double> {\n            double w = W[r + 1] - W[l];\n            double s = S[r + 1] - S[l];\n            double q = Q[r + 1] - Q[l];\n            if (w < 1e-12) return {INIT_COST, 0.0, 0.0};\n            double m = s / w;\n            double err = q - s * s / w;\n            return {m, err, w};\n        };\n\n        auto [m1, e1, _w1] = seg(0, 28);\n\n        double best2 = 1e100;\n        int bestk = -1;\n        double ml = m1, mr = m1;\n        for (int k = 1; k <= 28; ++k) {\n            auto [a, ea, _wa] = seg(0, k - 1);\n            auto [b, eb, _wb] = seg(k, 28);\n            double tot = ea + eb;\n            if (tot < best2) {\n                best2 = tot;\n                bestk = k;\n                ml = a;\n                mr = b;\n            }\n        }\n\n        res.diff = fabs(ml - mr);\n        res.improve = (e1 > 1e-9 ? 1.0 - best2 / e1 : 0.0);\n\n        bool two = false;\n        if (bestk != -1 && e1 > 1e-9) {\n            if (best2 < e1 * 0.80 && fabs(ml - mr) > 220.0) two = true;\n        }\n        res.use_two = two;\n\n        if (!two) {\n            for (int i = 0; i < 29; ++i) res.out[i] = m1;\n        } else {\n            for (int i = 0; i < bestk; ++i) res.out[i] = ml;\n            for (int i = bestk; i < 29; ++i) res.out[i] = mr;\n        }\n\n        for (int i = 0; i < 29; ++i) res.out[i] = clampd(res.out[i], MIN_COST, MAX_COST);\n        return res;\n    }\n\n    Observation make_observation(const Path& path, double y) {\n        Observation ob;\n        ob.edges = path.edges;\n        ob.len = (int)path.edges.size();\n        ob.y = y;\n        ob.w = 1.0 / max(1, ob.len);\n\n        for (int e : path.edges) {\n            if (e < HN) {\n                int r = e / 29;\n                ob.hcnt[r]++;\n            } else {\n                int id = e - HN;\n                int c = id % 30;\n                ob.vcnt[c]++;\n            }\n        }\n        return ob;\n    }\n\n    void solve_coarse_model() {\n        if (hist.empty()) {\n            for (int i = 0; i < 30; ++i) {\n                rowAvgH[i] = INIT_COST;\n                colAvgV[i] = INIT_COST;\n            }\n            return;\n        }\n\n        static double A[60][61];\n        for (int i = 0; i < 60; ++i) {\n            for (int j = 0; j <= 60; ++j) A[i][j] = 0.0;\n        }\n\n        int nobs = (int)hist.size();\n        double lambda = 1.2 / sqrt((double)nobs + 1.0) + 0.12;\n\n        for (int p = 0; p < 60; ++p) {\n            A[p][p] += lambda;\n            A[p][60] += lambda * INIT_COST;\n        }\n\n        vector<pair<int, double>> feats;\n        feats.reserve(60);\n\n        for (const auto& ob : hist) {\n            feats.clear();\n            for (int r = 0; r < 30; ++r) if (ob.hcnt[r]) feats.push_back({r, (double)ob.hcnt[r]});\n            for (int c = 0; c < 30; ++c) if (ob.vcnt[c]) feats.push_back({30 + c, (double)ob.vcnt[c]});\n\n            double w = ob.w;\n            for (auto [i, vi] : feats) A[i][60] += w * vi * ob.y;\n            for (auto [i, vi] : feats) {\n                for (auto [j, vj] : feats) {\n                    A[i][j] += w * vi * vj;\n                }\n            }\n        }\n\n        for (int col = 0; col < 60; ++col) {\n            int pivot = col;\n            for (int r = col + 1; r < 60; ++r) {\n                if (fabs(A[r][col]) > fabs(A[pivot][col])) pivot = r;\n            }\n            if (fabs(A[pivot][col]) < 1e-12) continue;\n\n            if (pivot != col) {\n                for (int j = col; j <= 60; ++j) swap(A[pivot][j], A[col][j]);\n            }\n\n            double div = A[col][col];\n            for (int j = col; j <= 60; ++j) A[col][j] /= div;\n\n            for (int r = 0; r < 60; ++r) {\n                if (r == col) continue;\n                double fac = A[r][col];\n                if (fabs(fac) < 1e-12) continue;\n                for (int j = col; j <= 60; ++j) A[r][j] -= fac * A[col][j];\n            }\n        }\n\n        for (int r = 0; r < 30; ++r) rowAvgH[r] = clampd(A[r][60], MIN_COST, MAX_COST);\n        for (int c = 0; c < 30; ++c) colAvgV[c] = clampd(A[30 + c][60], MIN_COST, MAX_COST);\n    }\n\n    void build_prior() {\n        solve_coarse_model();\n\n        for (int i = 0; i < 30; ++i)\n            for (int j = 0; j < 29; ++j)\n                prior[hid(i, j)] = rowAvgH[i];\n\n        for (int j = 0; j < 30; ++j)\n            for (int i = 0; i < 29; ++i)\n                prior[vid(i, j)] = colAvgV[j];\n\n        for (int i = 0; i < 30; ++i) {\n            int sumv = 0;\n            array<double, 29> val{}, wt{};\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                val[j] = x[e];\n                wt[j] = vis[e] + 2.0;\n                sumv += vis[e];\n            }\n            if (sumv < 12) continue;\n\n            auto fr = fit_piecewise_29(val, wt);\n            if (!fr.use_two || fr.improve < 0.20) continue;\n\n            double beta = 0.15 + 0.25 * ((double)sumv / ((double)sumv + 20.0));\n            beta = min(beta, 0.40);\n\n            for (int j = 0; j < 29; ++j) {\n                int e = hid(i, j);\n                prior[e] = clampd((1.0 - beta) * prior[e] + beta * fr.out[j], MIN_COST, MAX_COST);\n            }\n        }\n\n        for (int j = 0; j < 30; ++j) {\n            int sumv = 0;\n            array<double, 29> val{}, wt{};\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                val[i] = x[e];\n                wt[i] = vis[e] + 2.0;\n                sumv += vis[e];\n            }\n            if (sumv < 12) continue;\n\n            auto fr = fit_piecewise_29(val, wt);\n            if (!fr.use_two || fr.improve < 0.20) continue;\n\n            double beta = 0.15 + 0.25 * ((double)sumv / ((double)sumv + 20.0));\n            beta = min(beta, 0.40);\n\n            for (int i = 0; i < 29; ++i) {\n                int e = vid(i, j);\n                prior[e] = clampd((1.0 - beta) * prior[e] + beta * fr.out[i], MIN_COST, MAX_COST);\n            }\n        }\n    }\n\n    Path random_monotone_path(int si, int sj, int ti, int tj) {\n        Path p;\n        int i = si, j = sj;\n        int rv = abs(ti - si);\n        int rh = abs(tj - sj);\n        char mv_v = (ti > si ? 'D' : 'U');\n        char mv_h = (tj > sj ? 'R' : 'L');\n\n        p.s.reserve(rv + rh);\n        p.edges.reserve(rv + rh);\n\n        while (rv > 0 || rh > 0) {\n            bool take_v;\n            if (rv == 0) take_v = false;\n            else if (rh == 0) take_v = true;\n            else take_v = (randint(1, rv + rh) <= rv);\n\n            if (take_v) {\n                int e;\n                if (mv_v == 'D') {\n                    e = vid(i, j);\n                    ++i;\n                } else {\n                    e = vid(i - 1, j);\n                    --i;\n                }\n                p.s.push_back(mv_v);\n                p.edges.push_back(e);\n                --rv;\n            } else {\n                int e;\n                if (mv_h == 'R') {\n                    e = hid(i, j);\n                    ++j;\n                } else {\n                    e = hid(i, j - 1);\n                    --j;\n                }\n                p.s.push_back(mv_h);\n                p.edges.push_back(e);\n                --rh;\n            }\n        }\n        finalize_path(p);\n        return p;\n    }\n\n    Path ordered_monotone_path(int si, int sj, int ti, int tj, bool horiz_first) {\n        Path p;\n        int i = si, j = sj;\n        int rh = abs(tj - sj);\n        int rv = abs(ti - si);\n        char ch = (tj > sj ? 'R' : 'L');\n        char cv = (ti > si ? 'D' : 'U');\n\n        p.s.reserve(rh + rv);\n        p.edges.reserve(rh + rv);\n\n        auto step_h = [&](char c) {\n            int e;\n            if (c == 'R') {\n                e = hid(i, j);\n                ++j;\n            } else {\n                e = hid(i, j - 1);\n                --j;\n            }\n            p.s.push_back(c);\n            p.edges.push_back(e);\n        };\n\n        auto step_v = [&](char c) {\n            int e;\n            if (c == 'D') {\n                e = vid(i, j);\n                ++i;\n            } else {\n                e = vid(i - 1, j);\n                --i;\n            }\n            p.s.push_back(c);\n            p.edges.push_back(e);\n        };\n\n        if (horiz_first) {\n            while (rh--) step_h(ch);\n            while (rv--) step_v(cv);\n        } else {\n            while (rv--) step_v(cv);\n            while (rh--) step_h(ch);\n        }\n\n        finalize_path(p);\n        return p;\n    }\n\n    double search_cost_adaptive(int e, double ucoef) const {\n        return plan_edge(e) + ucoef * unc_edge(e);\n    }\n\n    double search_cost_fixedmix(int e, double lambda_x, double ucoef) const {\n        double c = lambda_x * est_edge(e) + (1.0 - lambda_x) * prior[e];\n        c = clampd(c, MIN_COST, MAX_COST);\n        return c + ucoef * unc_edge(e);\n    }\n\n    double search_cost_maxrisk(int e, double ucoef) const {\n        double c = max(est_edge(e), prior[e]);\n        return c + ucoef * unc_edge(e);\n    }\n\n    template <class CostFunc>\n    Path dijkstra_generic(int si, int sj, int ti, int tj, double step_penalty, CostFunc costf) const {\n        const int V = N * N;\n        const double INF = 1e100;\n\n        vector<double> dist(V, INF);\n        vector<int> parent(V, -1), parent_edge(V, -1);\n        vector<char> parent_char(V, '?');\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        int s = node_id(si, sj), t = node_id(ti, tj);\n        dist[s] = 0.0;\n        pq.push({0.0, s});\n\n        auto relax = [&](int v, int ni, int nj, int e, char c) {\n            int nv = node_id(ni, nj);\n            double nd = dist[v] + costf(e) + step_penalty;\n            if (nd + 1e-12 < dist[nv]) {\n                dist[nv] = nd;\n                parent[nv] = v;\n                parent_edge[nv] = e;\n                parent_char[nv] = c;\n                pq.push({nd, nv});\n            }\n        };\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d > dist[v] + 1e-12) continue;\n            if (v == t) break;\n\n            int i = v / N;\n            int j = v % N;\n\n            if (i > 0) relax(v, i - 1, j, vid(i - 1, j), 'U');\n            if (i + 1 < N) relax(v, i + 1, j, vid(i, j), 'D');\n            if (j > 0) relax(v, i, j - 1, hid(i, j - 1), 'L');\n            if (j + 1 < N) relax(v, i, j + 1, hid(i, j), 'R');\n        }\n\n        Path res;\n        vector<char> rs;\n        vector<int> re;\n        for (int cur = t; cur != s; cur = parent[cur]) {\n            rs.push_back(parent_char[cur]);\n            re.push_back(parent_edge[cur]);\n        }\n        reverse(rs.begin(), rs.end());\n        reverse(re.begin(), re.end());\n\n        res.s.assign(rs.begin(), rs.end());\n        res.edges = move(re);\n        finalize_path(res);\n        return res;\n    }\n\n    Path dijkstra_adaptive(int si, int sj, int ti, int tj, double step_penalty, double ucoef) const {\n        return dijkstra_generic(si, sj, ti, tj, step_penalty,\n                                [&](int e) { return search_cost_adaptive(e, ucoef); });\n    }\n\n    Path dijkstra_fixedmix(int si, int sj, int ti, int tj, double step_penalty, double lambda_x, double ucoef) const {\n        return dijkstra_generic(si, sj, ti, tj, step_penalty,\n                                [&](int e) { return search_cost_fixedmix(e, lambda_x, ucoef); });\n    }\n\n    Path dijkstra_maxrisk(int si, int sj, int ti, int tj, double step_penalty, double ucoef) const {\n        return dijkstra_generic(si, sj, ti, tj, step_penalty,\n                                [&](int e) { return search_cost_maxrisk(e, ucoef); });\n    }\n\n    double robust_score(const Path& p, int qidx, double explore_bonus) const {\n        double wx = stage_wx(qidx);\n        double wp = 1.0 - wx;\n        double ucoef = stage_ucoef(qidx);\n        double gcoef = stage_gcoef(qidx);\n\n        double sc = wx * p.sumX + wp * p.sumPrior + ucoef * p.sumUnc + gcoef * p.sumGap;\n        sc -= explore_bonus * p.sumUnc;\n        return sc;\n    }\n\n    Path choose_path(int si, int sj, int ti, int tj, int qidx) {\n        bool explore = false;\n        int samples = 0;\n        double bonus = 0.0;\n\n        if (qidx < 90) {\n            explore = true;\n            samples = 18;\n            bonus = 230.0;\n        } else if (qidx < 150) {\n            explore = true;\n            samples = 8;\n            bonus = 160.0;\n        } else if (qidx < 320 && rand01() < 0.04) {\n            explore = true;\n            samples = 4;\n            bonus = 90.0;\n        }\n\n        double base_step = 35.0;\n        if (qidx < 220) base_step += 250.0 * (220 - qidx) / 220.0;\n\n        double u_adapt = (qidx < 160 ? 70.0 : qidx < 450 ? 40.0 : 20.0);\n        double u_soft  = (qidx < 160 ? 26.0 : qidx < 450 ? 14.0 : 7.0);\n        double u_x     = (qidx < 160 ? 100.0 : qidx < 450 ? 50.0 : 20.0);\n        double u_prior = (qidx < 160 ? 35.0 : qidx < 450 ? 20.0 : 10.0);\n        double u_max   = (qidx < 160 ? 45.0 : qidx < 450 ? 24.0 : 0.0);\n\n        double wx = stage_wx(qidx);\n        double u_stage = 0.5 * (u_adapt + u_soft);\n\n        vector<Path> cands;\n        cands.reserve(40);\n\n        cands.push_back(dijkstra_adaptive(si, sj, ti, tj, base_step, u_adapt));\n        cands.push_back(dijkstra_adaptive(si, sj, ti, tj, base_step, u_soft));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 1.0, u_x));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 0.0, u_prior));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, 0.5, u_adapt));\n        cands.push_back(dijkstra_fixedmix(si, sj, ti, tj, base_step, wx, u_stage)); // new stage-matched candidate\n\n        if (qidx < 450) {\n            cands.push_back(dijkstra_maxrisk(si, sj, ti, tj, base_step, u_max));\n        }\n\n        cands.push_back(ordered_monotone_path(si, sj, ti, tj, true));\n        cands.push_back(ordered_monotone_path(si, sj, ti, tj, false));\n\n        if (qidx < 220) {\n            cands.push_back(dijkstra_adaptive(si, sj, ti, tj, 0.0, u_adapt * 0.7));\n        }\n\n        if (explore) {\n            for (int t = 0; t < samples; ++t) {\n                cands.push_back(random_monotone_path(si, sj, ti, tj));\n            }\n        }\n\n        int best_id = 0;\n        double best_sc = robust_score(cands[0], qidx, explore ? bonus : 0.0);\n\n        for (int i = 1; i < (int)cands.size(); ++i) {\n            double sc = robust_score(cands[i], qidx, explore ? bonus : 0.0);\n            if (sc + 1e-12 < best_sc) {\n                best_sc = sc;\n                best_id = i;\n            } else if (fabs(sc - best_sc) < 1e-12) {\n                if (cands[i].edges.size() < cands[best_id].edges.size()) best_id = i;\n                else if (cands[i].edges.size() == cands[best_id].edges.size() &&\n                         cands[i].sumUnc + 1e-12 < cands[best_id].sumUnc) {\n                    best_id = i;\n                }\n            }\n        }\n        return cands[best_id];\n    }\n\n    void online_update(const Path& path, double y, int qidx) {\n        int m = (int)path.edges.size();\n        if (m == 0) return;\n\n        double pred = path.sumX;\n        double residual = y - pred;\n\n        double eta;\n        if (qidx < 120) eta = 0.30;\n        else if (qidx < 350) eta = 0.22;\n        else eta = 0.16;\n\n        vector<double> u(m);\n        double su = 0.0;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            u[k] = 1.0 / sqrt((double)vis[e] + 1.0);\n            su += u[k];\n        }\n        if (su < 1e-12) su = 1.0;\n\n        double scale = eta * residual / su;\n        for (int k = 0; k < m; ++k) {\n            int e = path.edges[k];\n            double delta = scale * u[k];\n            delta = clampd(delta, -900.0, 900.0);\n            x[e] = clampd(x[e] + delta, MIN_COST, MAX_COST);\n        }\n\n        for (int e : path.edges) vis[e]++;\n        hist.push_back(make_observation(path, y));\n    }\n\n    void global_refine() {\n        int nobs = (int)hist.size();\n        if (nobs == 0) return;\n\n        build_prior();\n\n        double lambda0 = 0.10 / sqrt((double)nobs + 1.0) + 0.020;\n        double lambda1 = 0.32 / sqrt((double)nobs + 1.0) + 0.035;\n\n        vector<double> alpha(E), rhs(E, 0.0);\n        for (int e = 0; e < E; ++e) {\n            alpha[e] = 1.0 / sqrt((double)vis[e] + 1.0);\n            rhs[e] = lambda0 * alpha[e] * prior[e];\n        }\n\n        for (const auto& ob : hist) {\n            double c = ob.w * ob.y;\n            for (int e : ob.edges) rhs[e] += c;\n        }\n\n        auto apply = [&](const vector<double>& p, vector<double>& out) {\n            out.assign(E, 0.0);\n\n            for (int e = 0; e < E; ++e) out[e] = lambda0 * alpha[e] * p[e];\n\n            for (const auto& ob : hist) {\n                double s = 0.0;\n                for (int e : ob.edges) s += p[e];\n                s *= ob.w;\n                for (int e : ob.edges) out[e] += s;\n            }\n\n            for (int i = 0; i < 30; ++i) {\n                for (int j = 0; j < 28; ++j) {\n                    int e1 = hid(i, j), e2 = hid(i, j + 1);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n\n            for (int j = 0; j < 30; ++j) {\n                for (int i = 0; i < 28; ++i) {\n                    int e1 = vid(i, j), e2 = vid(i + 1, j);\n                    double d = lambda1 * (p[e1] - p[e2]);\n                    out[e1] += d;\n                    out[e2] -= d;\n                }\n            }\n        };\n\n        vector<double> sol = x, r(E), p(E), Ap(E);\n        apply(sol, Ap);\n        for (int e = 0; e < E; ++e) r[e] = rhs[e] - Ap[e];\n        p = r;\n\n        double rs0 = dot_vec(r, r);\n        double rs = rs0;\n        if (rs < 1e-12) return;\n\n        const int ITERS = 28;\n        for (int it = 0; it < ITERS; ++it) {\n            apply(p, Ap);\n            double pAp = dot_vec(p, Ap);\n            if (pAp <= 1e-18) break;\n\n            double a = rs / pAp;\n            for (int e = 0; e < E; ++e) sol[e] += a * p[e];\n            for (int e = 0; e < E; ++e) r[e] -= a * Ap[e];\n\n            double rs_new = dot_vec(r, r);\n            if (rs_new < rs0 * 1e-10) break;\n\n            double b = rs_new / rs;\n            for (int e = 0; e < E; ++e) p[e] = r[e] + b * p[e];\n            rs = rs_new;\n        }\n\n        for (int e = 0; e < E; ++e) x[e] = clampd(sol[e], MIN_COST, MAX_COST);\n\n        for (int e = 0; e < E; ++e) {\n            double g = 0.10 / sqrt((double)vis[e] + 1.0);\n            x[e] = clampd((1.0 - g) * x[e] + g * prior[e], MIN_COST, MAX_COST);\n        }\n\n        build_prior();\n    }\n\n    bool should_refine(int qq) const {\n        if (qq <= 160) return qq % 20 == 0;\n        if (qq <= 400) return qq % 40 == 0;\n        return qq % 50 == 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int q = 0; q < 1000; ++q) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        Path path = solver.choose_path(si, sj, ti, tj, q);\n\n        cout << path.s << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.online_update(path, (double)result, q);\n\n        int qq = q + 1;\n        if (solver.should_refine(qq)) {\n            solver.global_refine();\n        }\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nusing Matrix = array<unsigned char, N * N>;\n\nstruct Candidate {\n    string row;\n    vector<int> cover;\n    int totalWeight = 0;\n};\n\nstruct Move {\n    long long val;\n    string s;\n};\n\nstruct Edge {\n    int pid;\n    unsigned char req;\n};\n\nstruct StartResult {\n    long long score;\n    Matrix mat;\n};\n\nstruct RowState {\n    array<int, N> ord{};\n    array<int, N> sh{};\n    long long sc = LLONG_MIN;\n};\n\nstruct CellChange {\n    int cell;\n    unsigned char oldc;\n    unsigned char newc;\n};\n\nstatic chrono::steady_clock::time_point gStart;\nstatic inline long long elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - gStart\n    ).count();\n}\n\nmt19937 rng((unsigned)chrono::steady_clock::now().time_since_epoch().count());\n\n// compressed input\nvector<string> pats;\nvector<vector<unsigned char>> pch;\nvector<int> wt;\nvector<int> impOrder;\n\n// exact local search graph (all placements)\nvector<vector<Edge>> cellEdges; // 400 cells\nvector<int> plSid;\nvector<unsigned char> plLen;\nvector<unsigned char> plMatch;\n\n// vertical-only graph for zero-cost row operations\nvector<vector<Edge>> vCellEdges; // 400 cells\nvector<int> vPlSid;\nvector<unsigned char> vPlLen;\nvector<unsigned char> vPlMatch;\n\n// n-gram weights\nlong long pairW[8][8];\nlong long triW[8][8][8];\n\n// ---------------- row candidate generation utilities ----------------\n\ninline bool contains_in_doubled(const char* dd, const string& p) {\n    const int k = (int)p.size();\n    const char* ps = p.data();\n    for (int st = 0; st < N; ++st) {\n        int j = 0;\n        while (j < k && dd[st + j] == ps[j]) ++j;\n        if (j == k) return true;\n    }\n    return false;\n}\n\nint overlap_suffix_prefix(const string& a, const string& b) {\n    int lim = min((int)a.size(), (int)b.size());\n    for (int o = lim; o >= 1; --o) {\n        bool ok = true;\n        int sa = (int)a.size() - o;\n        for (int i = 0; i < o; ++i) {\n            if (a[sa + i] != b[i]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) return o;\n    }\n    return 0;\n}\n\nstring repeat_to_20(const string& s) {\n    if ((int)s.size() == N) return s;\n    string r(N, 'A');\n    for (int i = 0; i < N; ++i) r[i] = s[i % (int)s.size()];\n    return r;\n}\n\nstring min_rotation(const string& s) {\n    string best = s;\n    for (int sh = 1; sh < N; ++sh) {\n        string t = s.substr(sh) + s.substr(0, sh);\n        if (t < best) best = t;\n    }\n    return best;\n}\n\nvoid push_top(vector<Move>& top, long long val, const string& s, int cap = 4) {\n    if (val <= 0) return;\n    top.push_back({val, s});\n    int pos = (int)top.size() - 1;\n    while (pos > 0 && top[pos].val > top[pos - 1].val) {\n        swap(top[pos], top[pos - 1]);\n        --pos;\n    }\n    if ((int)top.size() > cap) top.pop_back();\n}\n\nstring choose_move(const vector<Move>& top, bool randomized) {\n    if (top.empty()) return \"\";\n    if (!randomized || top.size() == 1) return top[0].s;\n    int k = min<int>(3, top.size());\n    int r = (int)(rng() % 10);\n    int idx = 0;\n    if (k >= 3) {\n        if (r < 6) idx = 0;\n        else if (r < 9) idx = 1;\n        else idx = 2;\n    } else if (k == 2) {\n        idx = (r < 7 ? 0 : 1);\n    }\n    return top[idx].s;\n}\n\nstring build_candidate_row(int seedId, bool randomized) {\n    string cur = pats[seedId];\n    int scanLim = min<int>((int)impOrder.size(), 240);\n\n    // phase 0: strong overlap / containment\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            if ((int)x.size() > (int)cur.size()) {\n                if (x.find(cur) != string::npos && (int)x.size() <= N) {\n                    long long val = 1LL * wt[id] * 3000 + 1LL * ((int)x.size() - (int)cur.size()) * 200;\n                    push_top(top, val, x);\n                }\n            }\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if (ov > 0 && (int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 2000 + 1LL * ov * 800 - 1LL * add * 100;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty()) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    // phase 1: pack more strings\n    for (int iter = 0; iter < 24 && (int)cur.size() < N; ++iter) {\n        vector<Move> top;\n        for (int z = 0; z < scanLim; ++z) {\n            int id = impOrder[z];\n            const string& x = pats[id];\n            if (cur.find(x) != string::npos) continue;\n\n            {\n                int ov = overlap_suffix_prefix(cur, x);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = cur + x.substr(ov);\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n            {\n                int ov = overlap_suffix_prefix(x, cur);\n                int add = (int)x.size() - ov;\n                if ((int)cur.size() + add <= N) {\n                    string ns = x.substr(0, (int)x.size() - ov) + cur;\n                    long long val = 1LL * wt[id] * 500 + 1LL * ov * 80 - 1LL * add * 60;\n                    push_top(top, val, ns);\n                }\n            }\n        }\n        if (top.empty() || top[0].val <= 0) break;\n        string nxt = choose_move(top, randomized);\n        if (nxt.empty() || nxt == cur) break;\n        cur = nxt;\n    }\n\n    return repeat_to_20(cur);\n}\n\nvector<string> build_initial_rows(const vector<int>& charFreq) {\n    int U = (int)pats.size();\n    vector<Candidate> cands;\n    cands.reserve(400);\n\n    unordered_set<string> seen;\n    seen.reserve(2048);\n\n    auto add_candidate = [&](string row) {\n        if ((int)row.size() != N) row = repeat_to_20(row);\n        row = min_rotation(row);\n        if (!seen.insert(row).second) return;\n\n        char dd[40];\n        for (int i = 0; i < N; ++i) dd[i] = dd[i + N] = row[i];\n\n        Candidate cand;\n        cand.row = row;\n        cand.totalWeight = 0;\n        for (int id = 0; id < U; ++id) {\n            if (contains_in_doubled(dd, pats[id])) {\n                cand.cover.push_back(id);\n                cand.totalWeight += wt[id];\n            }\n        }\n        if (!cand.cover.empty()) cands.push_back(std::move(cand));\n    };\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n\n    for (int c = 0; c < 8; ++c) add_candidate(string(N, char('A' + c)));\n\n    for (int t = 0; t < min(U, 70); ++t) {\n        add_candidate(repeat_to_20(pats[impOrder[t]]));\n    }\n\n    for (int t = 0; t < min(U, 90); ++t) {\n        add_candidate(build_candidate_row(impOrder[t], false));\n        if (elapsed_ms() > 500) break;\n    }\n\n    for (int t = 0; t < 50; ++t) {\n        int lim = min(U, max(1, 40 + t * 2));\n        int seedId = impOrder[(int)(rng() % lim)];\n        add_candidate(build_candidate_row(seedId, true));\n        if (elapsed_ms() > 700) break;\n    }\n\n    if ((int)cands.size() < 20) {\n        for (int a = 0; a < 8; ++a) {\n            for (int b = 0; b < 8; ++b) {\n                string s(N, 'A');\n                for (int i = 0; i < N; ++i) s[i] = char('A' + ((i & 1) ? b : a));\n                add_candidate(s);\n                if ((int)cands.size() >= 20) break;\n            }\n            if ((int)cands.size() >= 20) break;\n        }\n    }\n\n    if (cands.empty()) {\n        vector<string> rows(20, string(N, char('A' + bestChar)));\n        return rows;\n    }\n\n    int C = (int)cands.size();\n\n    vector<int> selected;\n    selected.reserve(20);\n    vector<char> usedCand(C, 0);\n    vector<char> covered(U, 0);\n\n    for (int step = 0; step < 20 && step < C; ++step) {\n        int best = -1;\n        long long bestGain = -1;\n        int bestTotal = -1;\n        for (int ci = 0; ci < C; ++ci) if (!usedCand[ci]) {\n            long long gain = 0;\n            for (int id : cands[ci].cover) if (!covered[id]) gain += wt[id];\n            if (gain > bestGain || (gain == bestGain && cands[ci].totalWeight > bestTotal)) {\n                bestGain = gain;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n        if (best == -1) break;\n        usedCand[best] = 1;\n        selected.push_back(best);\n        for (int id : cands[best].cover) covered[id] = 1;\n    }\n\n    if ((int)selected.size() < 20) {\n        vector<int> ord(C);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return cands[a].totalWeight > cands[b].totalWeight;\n        });\n        for (int ci : ord) {\n            if ((int)selected.size() >= 20) break;\n            if (!usedCand[ci]) {\n                usedCand[ci] = 1;\n                selected.push_back(ci);\n            }\n        }\n    }\n    while ((int)selected.size() < 20) selected.push_back(selected[0]);\n\n    vector<int> coverCnt(U, 0);\n    long long rowWeight = 0;\n    fill(usedCand.begin(), usedCand.end(), 0);\n    for (int ci : selected) usedCand[ci] = 1;\n    for (int ci : selected) {\n        for (int id : cands[ci].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    for (int pos = 0; pos < 20; ++pos) {\n        int old = selected[pos];\n        usedCand[old] = 0;\n        for (int id : cands[old].cover) {\n            if (--coverCnt[id] == 0) rowWeight -= wt[id];\n        }\n\n        int best = old;\n        long long bestScore = rowWeight;\n        int bestTotal = cands[old].totalWeight;\n\n        for (int ci = 0; ci < C; ++ci) {\n            if (usedCand[ci]) continue;\n            long long sc = rowWeight;\n            for (int id : cands[ci].cover) {\n                if (coverCnt[id] == 0) sc += wt[id];\n            }\n            if (sc > bestScore || (sc == bestScore && cands[ci].totalWeight > bestTotal)) {\n                bestScore = sc;\n                bestTotal = cands[ci].totalWeight;\n                best = ci;\n            }\n        }\n\n        selected[pos] = best;\n        usedCand[best] = 1;\n        for (int id : cands[best].cover) {\n            if (coverCnt[id]++ == 0) rowWeight += wt[id];\n        }\n    }\n\n    vector<string> rows(20);\n    for (int i = 0; i < 20; ++i) rows[i] = cands[selected[i]].row;\n    return rows;\n}\n\n// ---------------- exact graph ----------------\n\nvoid build_exact_graph() {\n    int U = (int)pats.size();\n\n    cellEdges.assign(N * N, {});\n    vCellEdges.assign(N * N, {});\n\n    long long totalEdgesAll = 0;\n    long long totalEdgesV = 0;\n    for (int sid = 0; sid < U; ++sid) {\n        totalEdgesAll += 800LL * (int)pats[sid].size();\n        totalEdgesV += 400LL * (int)pats[sid].size();\n    }\n\n    int reserveAll = (int)(totalEdgesAll / (N * N)) + 64;\n    int reserveV = (int)(totalEdgesV / (N * N)) + 32;\n    for (int c = 0; c < N * N; ++c) {\n        cellEdges[c].reserve(reserveAll);\n        vCellEdges[c].reserve(reserveV);\n    }\n\n    plSid.clear();\n    plLen.clear();\n    plMatch.clear();\n    plSid.reserve(U * 800);\n    plLen.reserve(U * 800);\n    plMatch.reserve(U * 800);\n\n    vPlSid.clear();\n    vPlLen.clear();\n    vPlMatch.clear();\n    vPlSid.reserve(U * 400);\n    vPlLen.reserve(U * 400);\n    vPlMatch.reserve(U * 400);\n\n    for (int sid = 0; sid < U; ++sid) {\n        const auto& s = pch[sid];\n        int k = (int)s.size();\n\n        // horizontal placements\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n\n                int base = r * N;\n                for (int t = 0; t < k; ++t) {\n                    int cell = base + ((c + t) % N);\n                    cellEdges[cell].push_back({pid, s[t]});\n                }\n            }\n        }\n\n        // vertical placements\n        for (int c = 0; c < N; ++c) {\n            for (int r = 0; r < N; ++r) {\n                int pid = (int)plSid.size();\n                plSid.push_back(sid);\n                plLen.push_back((unsigned char)k);\n                plMatch.push_back(0);\n\n                int vpid = (int)vPlSid.size();\n                vPlSid.push_back(sid);\n                vPlLen.push_back((unsigned char)k);\n                vPlMatch.push_back(0);\n\n                for (int t = 0; t < k; ++t) {\n                    int cell = ((r + t) % N) * N + c;\n                    cellEdges[cell].push_back({pid, s[t]});\n                    vCellEdges[cell].push_back({vpid, s[t]});\n                }\n            }\n        }\n    }\n}\n\nlong long init_state(const Matrix& mat, vector<int>& fullCnt) {\n    fill(plMatch.begin(), plMatch.end(), 0);\n    for (int cell = 0; cell < N * N; ++cell) {\n        unsigned char ch = mat[cell];\n        for (const auto& e : cellEdges[cell]) {\n            if (e.req == ch) ++plMatch[e.pid];\n        }\n    }\n\n    fullCnt.assign(pats.size(), 0);\n    for (int pid = 0, P = (int)plSid.size(); pid < P; ++pid) {\n        if (plMatch[pid] == plLen[pid]) ++fullCnt[plSid[pid]];\n    }\n\n    long long score = 0;\n    for (int sid = 0; sid < (int)pats.size(); ++sid) {\n        if (fullCnt[sid] > 0) score += wt[sid];\n    }\n    return score;\n}\n\nvoid init_vertical_state(const Matrix& mat) {\n    fill(vPlMatch.begin(), vPlMatch.end(), 0);\n    for (int cell = 0; cell < N * N; ++cell) {\n        unsigned char ch = mat[cell];\n        for (const auto& e : vCellEdges[cell]) {\n            if (e.req == ch) ++vPlMatch[e.pid];\n        }\n    }\n}\n\n// ---------------- matrix utilities ----------------\n\nMatrix transpose_matrix(const Matrix& a) {\n    Matrix b{};\n    for (int r = 0; r < N; ++r)\n        for (int c = 0; c < N; ++c)\n            b[c * N + r] = a[r * N + c];\n    return b;\n}\n\nMatrix make_matrix_from_rows(const vector<string>& rows, bool randomizeOrderShift, bool doTranspose) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    if (randomizeOrderShift) shuffle(ord.begin(), ord.end(), rng);\n\n    Matrix mat{};\n    for (int r = 0; r < N; ++r) {\n        const string& s = rows[ord[r]];\n        int sh = randomizeOrderShift ? (int)(rng() % N) : 0;\n        for (int c = 0; c < N; ++c) mat[r * N + c] = (unsigned char)(s[(c + sh) % N] - 'A');\n    }\n    if (doTranspose) mat = transpose_matrix(mat);\n    return mat;\n}\n\nMatrix make_constant_matrix(int ch) {\n    Matrix mat{};\n    for (int i = 0; i < N * N; ++i) mat[i] = (unsigned char)ch;\n    return mat;\n}\n\nMatrix make_random_freq_matrix(const vector<int>& charFreq) {\n    array<int, 8> pref{};\n    pref[0] = charFreq[0];\n    for (int i = 1; i < 8; ++i) pref[i] = pref[i - 1] + charFreq[i];\n    int total = pref[7];\n    Matrix mat{};\n    for (int i = 0; i < N * N; ++i) {\n        int x = (int)(rng() % total);\n        int ch = 0;\n        while (pref[ch] <= x) ++ch;\n        mat[i] = (unsigned char)ch;\n    }\n    return mat;\n}\n\nvector<string> extract_rows(const Matrix& mat) {\n    vector<string> rows(N, string(N, 'A'));\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) rows[r][c] = char('A' + mat[r * N + c]);\n    }\n    return rows;\n}\n\n// ---------------- row order / shift optimization by n-grams ----------------\n\nvector<Matrix> build_ngram_starts(const vector<string>& rows) {\n    unsigned char rowChars[N][N][N];\n    for (int r = 0; r < N; ++r) {\n        for (int sh = 0; sh < N; ++sh) {\n            for (int c = 0; c < N; ++c) {\n                rowChars[r][sh][c] = (unsigned char)(rows[r][(c + sh) % N] - 'A');\n            }\n        }\n    }\n\n    auto totalScore = [&](const array<int, N>& ord, const array<int, N>& sh) -> long long {\n        long long sc = 0;\n        for (int p = 0; p < N; ++p) {\n            int a = ord[p];\n            int b = ord[(p + 1) % N];\n            int c = ord[(p + 2) % N];\n            int sa = sh[p];\n            int sb = sh[(p + 1) % N];\n            int scv = sh[(p + 2) % N];\n            for (int col = 0; col < N; ++col) {\n                unsigned char x = rowChars[a][sa][col];\n                unsigned char y = rowChars[b][sb][col];\n                unsigned char z = rowChars[c][scv][col];\n                sc += pairW[x][y];\n                sc += 2LL * triW[x][y][z];\n            }\n        }\n        return sc;\n    };\n\n    auto optimize_state = [&](RowState st) -> RowState {\n        st.sc = totalScore(st.ord, st.sh);\n\n        for (int it = 0; it < 8; ++it) {\n            bool improved = false;\n\n            // shifts\n            for (int p = 0; p < N; ++p) {\n                int bestSh = st.sh[p];\n                long long bestSc = st.sc;\n                int old = st.sh[p];\n                for (int cand = 0; cand < N; ++cand) {\n                    st.sh[p] = cand;\n                    long long sc = totalScore(st.ord, st.sh);\n                    if (sc > bestSc) {\n                        bestSc = sc;\n                        bestSh = cand;\n                    }\n                }\n                st.sh[p] = bestSh;\n                if (bestSc > st.sc) {\n                    st.sc = bestSc;\n                    improved = true;\n                } else {\n                    st.sh[p] = old;\n                }\n            }\n\n            // swaps\n            while (true) {\n                int bi = -1, bj = -1;\n                long long bestSc = st.sc;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = i + 1; j < N; ++j) {\n                        swap(st.ord[i], st.ord[j]);\n                        swap(st.sh[i], st.sh[j]);\n                        long long sc = totalScore(st.ord, st.sh);\n                        swap(st.ord[i], st.ord[j]);\n                        swap(st.sh[i], st.sh[j]);\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                swap(st.ord[bi], st.ord[bj]);\n                swap(st.sh[bi], st.sh[bj]);\n                st.sc = bestSc;\n                improved = true;\n            }\n\n            // insertions\n            while (true) {\n                int bi = -1, bj = -1;\n                long long bestSc = st.sc;\n                for (int i = 0; i < N; ++i) {\n                    for (int j = 0; j < N; ++j) {\n                        if (i == j) continue;\n                        RowState tmp = st;\n                        int ro = tmp.ord[i], rs = tmp.sh[i];\n                        if (i < j) {\n                            for (int t = i; t < j; ++t) {\n                                tmp.ord[t] = tmp.ord[t + 1];\n                                tmp.sh[t] = tmp.sh[t + 1];\n                            }\n                            tmp.ord[j] = ro;\n                            tmp.sh[j] = rs;\n                        } else {\n                            for (int t = i; t > j; --t) {\n                                tmp.ord[t] = tmp.ord[t - 1];\n                                tmp.sh[t] = tmp.sh[t - 1];\n                            }\n                            tmp.ord[j] = ro;\n                            tmp.sh[j] = rs;\n                        }\n                        long long sc = totalScore(tmp.ord, tmp.sh);\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bi = i;\n                            bj = j;\n                        }\n                    }\n                }\n                if (bi == -1) break;\n                int ro = st.ord[bi], rs = st.sh[bi];\n                if (bi < bj) {\n                    for (int t = bi; t < bj; ++t) {\n                        st.ord[t] = st.ord[t + 1];\n                        st.sh[t] = st.sh[t + 1];\n                    }\n                    st.ord[bj] = ro;\n                    st.sh[bj] = rs;\n                } else {\n                    for (int t = bi; t > bj; --t) {\n                        st.ord[t] = st.ord[t - 1];\n                        st.sh[t] = st.sh[t - 1];\n                    }\n                    st.ord[bj] = ro;\n                    st.sh[bj] = rs;\n                }\n                st.sc = bestSc;\n                improved = true;\n            }\n\n            if (!improved) break;\n        }\n\n        return st;\n    };\n\n    vector<RowState> states;\n    auto make_state = [&](bool randOrd, bool randSh) {\n        RowState st;\n        for (int i = 0; i < N; ++i) st.ord[i] = i;\n        if (randOrd) shuffle(st.ord.begin(), st.ord.end(), rng);\n        for (int i = 0; i < N; ++i) st.sh[i] = randSh ? (int)(rng() % N) : 0;\n        return optimize_state(st);\n    };\n\n    states.push_back(make_state(false, false));\n    states.push_back(make_state(false, true));\n    states.push_back(make_state(true, false));\n    for (int t = 0; t < 4; ++t) states.push_back(make_state(true, true));\n\n    sort(states.begin(), states.end(), [&](const RowState& a, const RowState& b) {\n        return a.sc > b.sc;\n    });\n\n    auto state_to_matrix = [&](const RowState& st, bool transposed) {\n        Matrix mat{};\n        for (int r = 0; r < N; ++r) {\n            int rowId = st.ord[r];\n            int sh = st.sh[r];\n            for (int c = 0; c < N; ++c) {\n                mat[r * N + c] = rowChars[rowId][sh][c];\n            }\n        }\n        if (transposed) mat = transpose_matrix(mat);\n        return mat;\n    };\n\n    vector<Matrix> starts;\n    int lim = min<int>(4, states.size());\n    for (int i = 0; i < lim; ++i) {\n        starts.push_back(state_to_matrix(states[i], false));\n        starts.push_back(state_to_matrix(states[i], true));\n    }\n    return starts;\n}\n\n// ---------------- soft refinement ----------------\n\nStartResult soft_refine(Matrix mat, const vector<int>& kinds, const vector<int>& inertias, long long deadlineMs) {\n    vector<int> tmpFull;\n    StartResult best{init_state(mat, tmpFull), mat};\n\n    for (int pi = 0; pi < (int)kinds.size(); ++pi) {\n        if (elapsed_ms() > deadlineMs) break;\n\n        int kind = kinds[pi];\n        int inertia = inertias[pi];\n\n        long long votes[N * N][8];\n        memset(votes, 0, sizeof(votes));\n\n        for (int cell = 0; cell < N * N; ++cell) votes[cell][mat[cell]] += inertia;\n\n        unsigned char row2[N][2 * N];\n        unsigned char col2[N][2 * N];\n        for (int r = 0; r < N; ++r)\n            for (int c = 0; c < 2 * N; ++c)\n                row2[r][c] = mat[r * N + (c % N)];\n        for (int c = 0; c < N; ++c)\n            for (int r = 0; r < 2 * N; ++r)\n                col2[c][r] = mat[(r % N) * N + c];\n\n        for (int sid = 0; sid < (int)pats.size(); ++sid) {\n            const auto& s = pch[sid];\n            int k = (int)s.size();\n\n            unsigned char scs[800];\n            int idx = 0;\n            int bestSc = -1;\n\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (row2[r][c + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n            for (int c = 0; c < N; ++c) {\n                for (int r = 0; r < N; ++r) {\n                    int sc = 0;\n                    for (int t = 0; t < k; ++t) sc += (col2[c][r + t] == s[t]);\n                    scs[idx++] = (unsigned char)sc;\n                    if (sc > bestSc) bestSc = sc;\n                }\n            }\n\n            int req, band;\n            long long base0, base1, base2;\n\n            if (kind == 0) {\n                req = max(3, (k + 1) / 2);\n                band = 0;\n                base0 = 64; base1 = 0; base2 = 0;\n            } else if (kind == 1) {\n                req = max(3, k / 2);\n                band = 1;\n                base0 = 48; base1 = 10; base2 = 0;\n            } else if (kind == 2) {\n                req = max(2, (k - 1) / 2);\n                band = 1;\n                base0 = 40; base1 = 14; base2 = 0;\n            } else if (kind == 3) {\n                req = 2;\n                band = 2;\n                base0 = 32; base1 = 12; base2 = 4;\n            } else if (kind == 4) {\n                req = max(2, k / 3);\n                band = 2;\n                base0 = 28; base1 = 12; base2 = 4;\n            } else {\n                req = 2;\n                band = 2;\n                base0 = 20; base1 = 10; base2 = 5;\n            }\n\n            if (bestSc < req) continue;\n\n            const int cap0 = 6, cap1 = 4, cap2 = 2;\n            int sel0[cap0], sel1[cap1], sel2[cap2];\n            int n0 = 0, n1 = 0, n2 = 0;\n            int seen0 = 0, seen1 = 0, seen2 = 0;\n\n            auto reservoir_add = [&](int* arr, int& n, int cap, int& seen, int code) {\n                ++seen;\n                if (n < cap) {\n                    arr[n++] = code;\n                } else {\n                    int r = (int)(rng() % seen);\n                    if (r < cap) arr[r] = code;\n                }\n            };\n\n            for (int code = 0; code < 800; ++code) {\n                int d = bestSc - (int)scs[code];\n                if (d == 0) reservoir_add(sel0, n0, cap0, seen0, code);\n                else if (d == 1 && band >= 1) reservoir_add(sel1, n1, cap1, seen1, code);\n                else if (d == 2 && band >= 2) reservoir_add(sel2, n2, cap2, seen2, code);\n            }\n\n            long long total0 = 1LL * wt[sid] * k * base0;\n            long long total1 = 1LL * wt[sid] * k * base1;\n            long long total2 = 1LL * wt[sid] * k * base2;\n\n            auto add_code = [&](int code, long long w) {\n                if (w <= 0) return;\n                if (code < 400) {\n                    int r = code / N;\n                    int c = code % N;\n                    int base = r * N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = base + ((c + t) % N);\n                        votes[cell][s[t]] += w;\n                    }\n                } else {\n                    int x = code - 400;\n                    int c = x / N;\n                    int r = x % N;\n                    for (int t = 0; t < k; ++t) {\n                        int cell = ((r + t) % N) * N + c;\n                        votes[cell][s[t]] += w;\n                    }\n                }\n            };\n\n            if (n0 > 0) {\n                long long w = total0 / n0;\n                for (int i = 0; i < n0; ++i) add_code(sel0[i], w);\n            }\n            if (n1 > 0) {\n                long long w = total1 / n1;\n                for (int i = 0; i < n1; ++i) add_code(sel1[i], w);\n            }\n            if (n2 > 0) {\n                long long w = total2 / n2;\n                for (int i = 0; i < n2; ++i) add_code(sel2[i], w);\n            }\n        }\n\n        int changes = 0;\n        for (int cell = 0; cell < N * N; ++cell) {\n            unsigned char old = mat[cell];\n            unsigned char bestCh = old;\n            long long bestV = votes[cell][old];\n            for (unsigned char ch = 0; ch < 8; ++ch) {\n                if (votes[cell][ch] > bestV) {\n                    bestV = votes[cell][ch];\n                    bestCh = ch;\n                }\n            }\n            if (bestCh != old) {\n                mat[cell] = bestCh;\n                ++changes;\n            }\n        }\n\n        long long sc = init_state(mat, tmpFull);\n        if (sc > best.score) best = {sc, mat};\n        if (changes == 0) break;\n    }\n\n    return best;\n}\n\n// ---------------- exact hill-climb ----------------\n\nStartResult exact_hillclimb(Matrix mat, int maxPass, long long endMs) {\n    vector<int> fullCnt;\n    long long curScore = init_state(mat, fullCnt);\n    StartResult best{curScore, mat};\n\n    vector<int> order(N * N);\n    iota(order.begin(), order.end(), 0);\n\n    int U = (int)pats.size();\n    vector<int> seen(U, 0), inc(U, 0), dec(U, 0), touched;\n    touched.reserve(U);\n    int stamp = 1;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        if (elapsed_ms() > endMs) break;\n        shuffle(order.begin(), order.end(), rng);\n        bool improved = false;\n\n        for (int cell : order) {\n            if (elapsed_ms() > endMs) break;\n\n            unsigned char old = mat[cell];\n            long long bestDelta = 0;\n            unsigned char bestCh = old;\n\n            for (unsigned char nw = 0; nw < 8; ++nw) {\n                if (nw == old) continue;\n                ++stamp;\n                touched.clear();\n\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == nw);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n\n                    if (seen[sid] != stamp) {\n                        seen[sid] = stamp;\n                        inc[sid] = 0;\n                        dec[sid] = 0;\n                        touched.push_back(sid);\n                    }\n\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) ++dec[sid];\n                    } else {\n                        if ((int)plMatch[pid] + 1 == (int)plLen[pid]) ++inc[sid];\n                    }\n                }\n\n                long long delta = 0;\n                for (int sid : touched) {\n                    int oldCnt = fullCnt[sid];\n                    int newCnt = oldCnt - dec[sid] + inc[sid];\n                    if (oldCnt == 0 && newCnt > 0) delta += wt[sid];\n                    else if (oldCnt > 0 && newCnt == 0) delta -= wt[sid];\n                }\n\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestCh = nw;\n                }\n            }\n\n            if (bestCh != old) {\n                for (const auto& e : cellEdges[cell]) {\n                    bool had = (e.req == old);\n                    bool will = (e.req == bestCh);\n                    if (had == will) continue;\n\n                    int pid = e.pid;\n                    int sid = plSid[pid];\n                    if (had) {\n                        if (plMatch[pid] == plLen[pid]) --fullCnt[sid];\n                        --plMatch[pid];\n                    } else {\n                        ++plMatch[pid];\n                        if (plMatch[pid] == plLen[pid]) ++fullCnt[sid];\n                    }\n                }\n                mat[cell] = bestCh;\n                curScore += bestDelta;\n                improved = true;\n                if (curScore > best.score) best = {curScore, mat};\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return best;\n}\n\n// ---------------- exact zero-cost row optimizer ----------------\n\nlong long compute_vertical_delta(\n    const CellChange* chgs, int m,\n    const vector<int>& totalFullCnt,\n    vector<int>& pidSeen, vector<int>& pidDelta, int& pidStamp, vector<int>& touchedPid,\n    vector<int>& sidSeen, vector<int>& sidInc, vector<int>& sidDec, int& sidStamp, vector<int>& touchedSid\n) {\n    ++pidStamp;\n    if (pidStamp == INT_MAX) {\n        fill(pidSeen.begin(), pidSeen.end(), 0);\n        pidStamp = 1;\n    }\n    touchedPid.clear();\n\n    for (int i = 0; i < m; ++i) {\n        int cell = chgs[i].cell;\n        unsigned char oldc = chgs[i].oldc;\n        unsigned char newc = chgs[i].newc;\n        if (oldc == newc) continue;\n\n        for (const auto& e : vCellEdges[cell]) {\n            int vpid = e.pid;\n            if (pidSeen[vpid] != pidStamp) {\n                pidSeen[vpid] = pidStamp;\n                pidDelta[vpid] = 0;\n                touchedPid.push_back(vpid);\n            }\n            if (e.req == oldc) --pidDelta[vpid];\n            if (e.req == newc) ++pidDelta[vpid];\n        }\n    }\n\n    ++sidStamp;\n    if (sidStamp == INT_MAX) {\n        fill(sidSeen.begin(), sidSeen.end(), 0);\n        sidStamp = 1;\n    }\n    touchedSid.clear();\n\n    for (int vpid : touchedPid) {\n        int d = pidDelta[vpid];\n        if (d == 0) continue;\n        int sid = vPlSid[vpid];\n        if (sidSeen[sid] != sidStamp) {\n            sidSeen[sid] = sidStamp;\n            sidInc[sid] = 0;\n            sidDec[sid] = 0;\n            touchedSid.push_back(sid);\n        }\n\n        int oldm = vPlMatch[vpid];\n        int newm = oldm + d;\n        int len = vPlLen[vpid];\n\n        if (oldm == len && newm < len) ++sidDec[sid];\n        else if (oldm < len && newm == len) ++sidInc[sid];\n    }\n\n    long long delta = 0;\n    for (int sid : touchedSid) {\n        int oldCnt = totalFullCnt[sid];\n        int newCnt = oldCnt - sidDec[sid] + sidInc[sid];\n        if (oldCnt == 0 && newCnt > 0) delta += wt[sid];\n        else if (oldCnt > 0 && newCnt == 0) delta -= wt[sid];\n    }\n    return delta;\n}\n\nvoid apply_vertical_changes(\n    Matrix& mat,\n    const CellChange* chgs, int m,\n    vector<int>& totalFullCnt, long long& curScore,\n    vector<int>& pidSeen, vector<int>& pidDelta, int& pidStamp, vector<int>& touchedPid,\n    vector<int>& sidSeen, vector<int>& sidInc, vector<int>& sidDec, int& sidStamp, vector<int>& touchedSid\n) {\n    long long delta = compute_vertical_delta(\n        chgs, m, totalFullCnt,\n        pidSeen, pidDelta, pidStamp, touchedPid,\n        sidSeen, sidInc, sidDec, sidStamp, touchedSid\n    );\n\n    for (int vpid : touchedPid) {\n        int d = pidDelta[vpid];\n        if (d == 0) continue;\n        int oldm = vPlMatch[vpid];\n        int newm = oldm + d;\n        int sid = vPlSid[vpid];\n        int len = vPlLen[vpid];\n\n        if (oldm == len && newm < len) --totalFullCnt[sid];\n        else if (oldm < len && newm == len) ++totalFullCnt[sid];\n\n        vPlMatch[vpid] = (unsigned char)newm;\n    }\n\n    for (int i = 0; i < m; ++i) {\n        mat[chgs[i].cell] = chgs[i].newc;\n    }\n\n    curScore += delta;\n}\n\nStartResult exact_row_optimize(Matrix mat, long long endMs) {\n    vector<int> totalFullCnt;\n    long long curScore = init_state(mat, totalFullCnt);\n    init_vertical_state(mat);\n\n    const int U = (int)pats.size();\n    const int V = (int)vPlSid.size();\n\n    vector<int> pidSeen(V, 0), pidDelta(V, 0), touchedPid;\n    vector<int> sidSeen(U, 0), sidInc(U, 0), sidDec(U, 0), touchedSid;\n    touchedPid.reserve(160000);\n    touchedSid.reserve(U);\n\n    int pidStamp = 1, sidStamp = 1;\n\n    array<int, N> rowOrder{};\n    iota(rowOrder.begin(), rowOrder.end(), 0);\n\n    array<CellChange, N> shiftChg{};\n    array<CellChange, 2 * N> swapChg{};\n    array<CellChange, N * N> insChg{};\n\n    struct InsCand {\n        long long approx;\n        int i, j;\n    };\n    auto push_top_ins = [&](vector<InsCand>& top, long long approx, int i, int j, int cap = 8) {\n        top.push_back({approx, i, j});\n        int pos = (int)top.size() - 1;\n        while (pos > 0 && top[pos].approx > top[pos - 1].approx) {\n            swap(top[pos], top[pos - 1]);\n            --pos;\n        }\n        if ((int)top.size() > cap) top.pop_back();\n    };\n\n    auto approx_order_score = [&](const array<int, N>& ord) -> long long {\n        long long sc = 0;\n        for (int p = 0; p < N; ++p) {\n            int a = ord[p];\n            int b = ord[(p + 1) % N];\n            int c = ord[(p + 2) % N];\n            int ba = a * N, bb = b * N, bc = c * N;\n            for (int col = 0; col < N; ++col) {\n                unsigned char x = mat[ba + col];\n                unsigned char y = mat[bb + col];\n                unsigned char z = mat[bc + col];\n                sc += pairW[x][y];\n                sc += 2LL * triW[x][y][z];\n            }\n        }\n        return sc;\n    };\n\n    for (int outer = 0; outer < 2; ++outer) {\n        if (elapsed_ms() > endMs) break;\n        bool improved = false;\n\n        shuffle(rowOrder.begin(), rowOrder.end(), rng);\n\n        // row cyclic shifts\n        for (int rr = 0; rr < N; ++rr) {\n            if (elapsed_ms() > endMs) break;\n            int r = rowOrder[rr];\n            int base = r * N;\n\n            unsigned char oldRow[N];\n            for (int c = 0; c < N; ++c) oldRow[c] = mat[base + c];\n\n            long long bestDelta = 0;\n            int bestSh = 0;\n\n            for (int sh = 1; sh < N; ++sh) {\n                for (int c = 0; c < N; ++c) {\n                    shiftChg[c] = {base + c, oldRow[c], oldRow[(c + sh) % N]};\n                }\n\n                long long delta = compute_vertical_delta(\n                    shiftChg.data(), N, totalFullCnt,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestSh = sh;\n                }\n            }\n\n            if (bestSh != 0) {\n                for (int c = 0; c < N; ++c) {\n                    shiftChg[c] = {base + c, oldRow[c], oldRow[(c + bestSh) % N]};\n                }\n                apply_vertical_changes(\n                    mat, shiftChg.data(), N, totalFullCnt, curScore,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                improved = true;\n            }\n        }\n\n        if (elapsed_ms() > endMs) break;\n\n        // row swaps\n        for (int rep = 0; rep < 2; ++rep) {\n            if (elapsed_ms() > endMs) break;\n\n            long long bestDelta = 0;\n            int bi = -1, bj = -1;\n\n            for (int i = 0; i < N; ++i) {\n                if (elapsed_ms() > endMs) break;\n                int baseI = i * N;\n                for (int j = i + 1; j < N; ++j) {\n                    int baseJ = j * N;\n                    for (int c = 0; c < N; ++c) {\n                        swapChg[2 * c] = {baseI + c, mat[baseI + c], mat[baseJ + c]};\n                        swapChg[2 * c + 1] = {baseJ + c, mat[baseJ + c], mat[baseI + c]};\n                    }\n\n                    long long delta = compute_vertical_delta(\n                        swapChg.data(), 2 * N, totalFullCnt,\n                        pidSeen, pidDelta, pidStamp, touchedPid,\n                        sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                    );\n                    if (delta > bestDelta) {\n                        bestDelta = delta;\n                        bi = i;\n                        bj = j;\n                    }\n                }\n            }\n\n            if (bi == -1) break;\n\n            int baseI = bi * N;\n            int baseJ = bj * N;\n            for (int c = 0; c < N; ++c) {\n                swapChg[2 * c] = {baseI + c, mat[baseI + c], mat[baseJ + c]};\n                swapChg[2 * c + 1] = {baseJ + c, mat[baseJ + c], mat[baseI + c]};\n            }\n\n            apply_vertical_changes(\n                mat, swapChg.data(), 2 * N, totalFullCnt, curScore,\n                pidSeen, pidDelta, pidStamp, touchedPid,\n                sidSeen, sidInc, sidDec, sidStamp, touchedSid\n            );\n            improved = true;\n        }\n\n        if (elapsed_ms() > endMs) break;\n\n        // row insertions, shortlisted by n-gram score\n        for (int rep = 0; rep < 2; ++rep) {\n            if (elapsed_ms() > endMs) break;\n\n            array<int, N> ord{};\n            iota(ord.begin(), ord.end(), 0);\n            long long curApprox = approx_order_score(ord);\n\n            vector<InsCand> topIns;\n            topIns.reserve(8);\n\n            for (int i = 0; i < N; ++i) {\n                for (int j = 0; j < N; ++j) {\n                    if (i == j) continue;\n                    array<int, N> tmp = ord;\n                    int v = tmp[i];\n                    if (i < j) {\n                        for (int t = i; t < j; ++t) tmp[t] = tmp[t + 1];\n                        tmp[j] = v;\n                    } else {\n                        for (int t = i; t > j; --t) tmp[t] = tmp[t - 1];\n                        tmp[j] = v;\n                    }\n                    long long sc = approx_order_score(tmp);\n                    push_top_ins(topIns, sc - curApprox, i, j, 8);\n                }\n            }\n\n            unsigned char oldRows[N][N];\n            for (int r = 0; r < N; ++r) {\n                for (int c = 0; c < N; ++c) oldRows[r][c] = mat[r * N + c];\n            }\n\n            long long bestDelta = 0;\n            int bestI = -1, bestJ = -1;\n\n            for (auto cand : topIns) {\n                int i = cand.i, j = cand.j;\n                int m = 0;\n\n                if (i < j) {\n                    for (int r = i; r < j; ++r) {\n                        for (int c = 0; c < N; ++c) {\n                            insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r + 1][c]};\n                        }\n                    }\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {j * N + c, oldRows[j][c], oldRows[i][c]};\n                    }\n                } else {\n                    for (int r = i; r > j; --r) {\n                        for (int c = 0; c < N; ++c) {\n                            insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r - 1][c]};\n                        }\n                    }\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {j * N + c, oldRows[j][c], oldRows[i][c]};\n                    }\n                }\n\n                long long delta = compute_vertical_delta(\n                    insChg.data(), m, totalFullCnt,\n                    pidSeen, pidDelta, pidStamp, touchedPid,\n                    sidSeen, sidInc, sidDec, sidStamp, touchedSid\n                );\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n\n            if (bestI == -1) break;\n\n            int m = 0;\n            if (bestI < bestJ) {\n                for (int r = bestI; r < bestJ; ++r) {\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r + 1][c]};\n                    }\n                }\n                for (int c = 0; c < N; ++c) {\n                    insChg[m++] = {bestJ * N + c, oldRows[bestJ][c], oldRows[bestI][c]};\n                }\n            } else {\n                for (int r = bestI; r > bestJ; --r) {\n                    for (int c = 0; c < N; ++c) {\n                        insChg[m++] = {r * N + c, oldRows[r][c], oldRows[r - 1][c]};\n                    }\n                }\n                for (int c = 0; c < N; ++c) {\n                    insChg[m++] = {bestJ * N + c, oldRows[bestJ][c], oldRows[bestI][c]};\n                }\n            }\n\n            apply_vertical_changes(\n                mat, insChg.data(), m, totalFullCnt, curScore,\n                pidSeen, pidDelta, pidStamp, touchedPid,\n                sidSeen, sidInc, sidDec, sidStamp, touchedSid\n            );\n            improved = true;\n        }\n\n        if (!improved) break;\n    }\n\n    return {curScore, mat};\n}\n\n// ---------------- main ----------------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gStart = chrono::steady_clock::now();\n\n    int Nin, M;\n    cin >> Nin >> M;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M * 2);\n\n    vector<int> charFreq(8, 0);\n\n    for (int i = 0; i < M; ++i) {\n        string s;\n        cin >> s;\n        auto it = mp.find(s);\n        if (it == mp.end()) {\n            int id = (int)pats.size();\n            mp.emplace(s, id);\n            pats.push_back(s);\n            wt.push_back(1);\n        } else {\n            wt[it->second]++;\n        }\n        for (char c : s) ++charFreq[c - 'A'];\n    }\n\n    int U = (int)pats.size();\n    pch.resize(U);\n    for (int i = 0; i < U; ++i) {\n        pch[i].resize(pats[i].size());\n        for (int j = 0; j < (int)pats[i].size(); ++j) {\n            pch[i][j] = (unsigned char)(pats[i][j] - 'A');\n        }\n    }\n\n    memset(pairW, 0, sizeof(pairW));\n    memset(triW, 0, sizeof(triW));\n    for (int sid = 0; sid < U; ++sid) {\n        const auto& s = pch[sid];\n        int k = (int)s.size();\n        for (int i = 0; i + 1 < k; ++i) pairW[s[i]][s[i + 1]] += wt[sid];\n        for (int i = 0; i + 2 < k; ++i) triW[s[i]][s[i + 1]][s[i + 2]] += wt[sid];\n    }\n\n    vector<long long> imp(U);\n    for (int i = 0; i < U; ++i) {\n        int L = (int)pats[i].size();\n        imp[i] = 1LL * wt[i] * L * L;\n    }\n    impOrder.resize(U);\n    iota(impOrder.begin(), impOrder.end(), 0);\n    sort(impOrder.begin(), impOrder.end(), [&](int a, int b) {\n        if (imp[a] != imp[b]) return imp[a] > imp[b];\n        return pats[a].size() > pats[b].size();\n    });\n\n    // Stage 1: row assembly\n    vector<string> rows = build_initial_rows(charFreq);\n\n    // Stage 2: exact graph\n    build_exact_graph();\n\n    // Stage 3: build diverse starts\n    vector<Matrix> starts;\n\n    {\n        vector<Matrix> ng = build_ngram_starts(rows);\n        for (auto& m : ng) starts.push_back(m);\n    }\n\n    starts.push_back(make_matrix_from_rows(rows, false, false));\n    starts.push_back(make_matrix_from_rows(rows, false, true));\n    starts.push_back(make_matrix_from_rows(rows, true, false));\n    starts.push_back(make_matrix_from_rows(rows, true, true));\n\n    int bestChar = 0;\n    for (int c = 1; c < 8; ++c) if (charFreq[c] > charFreq[bestChar]) bestChar = c;\n    starts.push_back(make_constant_matrix(bestChar));\n    starts.push_back(make_random_freq_matrix(charFreq));\n\n    // soft refinement on starts\n    vector<StartResult> refined;\n    refined.reserve(starts.size());\n\n    long long softDeadline = 1650;\n    for (int i = 0; i < (int)starts.size(); ++i) {\n        if (elapsed_ms() > softDeadline) break;\n\n        vector<int> kinds, inertias;\n        if (elapsed_ms() < 1200) {\n            kinds = {0, 1, 2, 3};\n            inertias = {120, 60, 36, 20};\n        } else {\n            kinds = {0, 1, 2};\n            inertias = {100, 50, 28};\n        }\n\n        StartResult res = soft_refine(starts[i], kinds, inertias, softDeadline);\n        refined.push_back(res);\n    }\n\n    if (refined.empty()) {\n        vector<int> tmp;\n        refined.push_back({init_state(starts[0], tmp), starts[0]});\n    }\n\n    sort(refined.begin(), refined.end(), [&](const StartResult& a, const StartResult& b) {\n        return a.score > b.score;\n    });\n\n    StartResult globalBest = refined[0];\n\n    // exact hill-climb on top starts\n    long long hcEnd = 2520;\n    for (int i = 0; i < min<int>(2, refined.size()); ++i) {\n        if (elapsed_ms() > hcEnd) break;\n        int maxPass = (i == 0 ? 2 : 1);\n        StartResult res = exact_hillclimb(refined[i].mat, maxPass, hcEnd);\n        if (res.score > globalBest.score) globalBest = res;\n    }\n\n    // zero-cost structural polish: row shifts/swaps/insertions\n    if (elapsed_ms() < 2840) {\n        StartResult z = exact_row_optimize(globalBest.mat, 2840);\n        if (z.score >= globalBest.score) globalBest = z;\n    }\n\n    // transpose -> same polish -> transpose back\n    if (elapsed_ms() < 2925) {\n        Matrix t = transpose_matrix(globalBest.mat);\n        StartResult zt = exact_row_optimize(t, 2925);\n        zt.mat = transpose_matrix(zt.mat);\n        if (zt.score >= globalBest.score) globalBest = zt;\n    }\n\n    // final exact polish\n    if (elapsed_ms() < 2965) {\n        StartResult res = exact_hillclimb(globalBest.mat, 1, 2965);\n        if (res.score > globalBest.score) globalBest = res;\n    }\n\n    // light kick + exact polish\n    if (elapsed_ms() < 2985) {\n        StartResult kicked = soft_refine(globalBest.mat, {4}, {14}, 2990);\n        if (elapsed_ms() < 2995) {\n            StartResult res = exact_hillclimb(kicked.mat, 1, 2995);\n            if (res.score > globalBest.score) globalBest = res;\n            else if (kicked.score > globalBest.score) globalBest = kicked;\n        } else {\n            if (kicked.score > globalBest.score) globalBest = kicked;\n        }\n    }\n\n    // output\n    for (int r = 0; r < N; ++r) {\n        string out(N, 'A');\n        for (int c = 0; c < N; ++c) out[c] = char('A' + globalBest.mat[r * N + c]);\n        cout << out << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n#include <atcoder/mincostflow>\n\nusing namespace std;\nusing ll = long long;\nusing atcoder::mf_graph;\nusing atcoder::mcf_graph;\n\nstatic constexpr int INF_INT = 1e9;\nstatic constexpr ll INF_LL = (ll)4e18;\n\nstruct Task {\n    // type: 0=fixed cell, 1=horizontal segment, 2=vertical segment\n    int type;\n    int seg;\n    int cell;\n};\n\nstruct CandidateResult {\n    bool valid = false;\n    ll cost = INF_LL;\n    string path;\n};\n\nint N, si, sj;\nvector<string> gridc;\nvector<vector<int>> idg;\n\nint Rcnt, sId;\nvector<int> rr, cc, cellW;\nvector<vector<int>> nbrs;\n\nint Hcnt, Vcnt;\nvector<int> hid, vid;\nvector<vector<int>> cellsH, cellsV;\nvector<vector<pair<int,int>>> adjHFull, adjHRes; // (v, cell)\n\nint sH, sV;\nvector<char> activeH, activeV;\nvector<int> bestCellH, bestCellV;\nvector<int> distStart;\n\nvector<char> dijReady;\nvector<vector<int>> distCache, parentCache;\n\nchrono::steady_clock::time_point globalStart;\n\nll elapsed_ms() {\n    return chrono::duration_cast<chrono::milliseconds>(\n        chrono::steady_clock::now() - globalStart\n    ).count();\n}\n\nchar dirChar(int a, int b) {\n    if (rr[b] == rr[a] - 1 && cc[b] == cc[a]) return 'U';\n    if (rr[b] == rr[a] + 1 && cc[b] == cc[a]) return 'D';\n    if (rr[b] == rr[a] && cc[b] == cc[a] - 1) return 'L';\n    if (rr[b] == rr[a] && cc[b] == cc[a] + 1) return 'R';\n    return '?';\n}\n\nvoid runDijkstra(int src, vector<int>& dist, vector<int>& parent) {\n    dist.assign(Rcnt, INF_INT);\n    parent.assign(Rcnt, -1);\n    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n    dist[src] = 0;\n    pq.push({0, src});\n    while (!pq.empty()) {\n        auto [d, u] = pq.top();\n        pq.pop();\n        if (d != dist[u]) continue;\n        for (int v : nbrs[u]) {\n            int nd = d + cellW[v];\n            if (nd < dist[v]) {\n                dist[v] = nd;\n                parent[v] = u;\n                pq.push({nd, v});\n            }\n        }\n    }\n}\n\nvoid ensureDijkstra(int src) {\n    if (dijReady[src]) return;\n    dijReady[src] = true;\n    runDijkstra(src, distCache[src], parentCache[src]);\n}\n\npair<bool,ll> validateAndCost(const string& path) {\n    vector<char> covH(Hcnt, false), covV(Vcnt, false);\n    int cur = sId;\n    covH[hid[cur]] = true;\n    covV[vid[cur]] = true;\n    ll cost = 0;\n\n    for (char ch : path) {\n        int ni = rr[cur], nj = cc[cur];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return {false, 0};\n\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return {false, 0};\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return {false, 0};\n\n        cost += cellW[nxt];\n        cur = nxt;\n        covH[hid[cur]] = true;\n        covV[vid[cur]] = true;\n    }\n\n    if (cur != sId) return {false, 0};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        if (!covH[hid[cid]] && !covV[vid[cid]]) return {false, 0};\n    }\n    return {true, cost};\n}\n\nvoid hopcroftKarp(\n    const vector<char>& selH,\n    const vector<char>& selV,\n    const vector<vector<pair<int,int>>>& adj,\n    vector<int>& matchH,\n    vector<int>& matchV\n) {\n    matchH.assign(Hcnt, -1);\n    matchV.assign(Vcnt, -1);\n    vector<int> level(Hcnt, -1);\n\n    auto bfs = [&]() -> bool {\n        queue<int> q;\n        fill(level.begin(), level.end(), -1);\n        bool found = false;\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) {\n                level[h] = 0;\n                q.push(h);\n            }\n        }\n        while (!q.empty()) {\n            int h = q.front(); q.pop();\n            for (auto [v, cid] : adj[h]) {\n                (void)cid;\n                if (!selV[v]) continue;\n                int h2 = matchV[v];\n                if (h2 == -1) {\n                    found = true;\n                } else if (level[h2] == -1) {\n                    level[h2] = level[h] + 1;\n                    q.push(h2);\n                }\n            }\n        }\n        return found;\n    };\n\n    function<bool(int)> dfs = [&](int h) -> bool {\n        for (auto [v, cid] : adj[h]) {\n            (void)cid;\n            if (!selV[v]) continue;\n            int h2 = matchV[v];\n            if (h2 == -1 || (level[h2] == level[h] + 1 && dfs(h2))) {\n                matchH[h] = v;\n                matchV[v] = h;\n                return true;\n            }\n        }\n        level[h] = -1;\n        return false;\n    };\n\n    while (bfs()) {\n        for (int h = 0; h < Hcnt; h++) {\n            if (!selH[h]) continue;\n            if (matchH[h] == -1) dfs(h);\n        }\n    }\n}\n\npair<vector<char>, vector<char>> buildCanonicalMVC() {\n    vector<int> matchH, matchV;\n    hopcroftKarp(activeH, activeV, adjHRes, matchH, matchV);\n\n    vector<char> visH(Hcnt, false), visV(Vcnt, false);\n    queue<int> q;\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h] && matchH[h] == -1) {\n            visH[h] = true;\n            q.push(h);\n        }\n    }\n\n    while (!q.empty()) {\n        int h = q.front(); q.pop();\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (matchH[h] == v) continue;\n            if (!visV[v]) {\n                visV[v] = true;\n                int h2 = matchV[v];\n                if (h2 != -1 && !visH[h2]) {\n                    visH[h2] = true;\n                    q.push(h2);\n                }\n            }\n        }\n    }\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !visH[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && visV[v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\npair<vector<char>, vector<char>> buildWeightedVC(\n    const vector<ll>& wH,\n    const vector<ll>& wV\n) {\n    int S = Hcnt + Vcnt;\n    int T = S + 1;\n    mf_graph<ll> mf(T + 1);\n\n    for (int h = 0; h < Hcnt; h++) {\n        if (activeH[h]) mf.add_edge(S, h, wH[h]);\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        if (activeV[v]) mf.add_edge(Hcnt + v, T, wV[v]);\n    }\n    for (int h = 0; h < Hcnt; h++) {\n        if (!activeH[h]) continue;\n        for (auto [v, cid] : adjHRes[h]) {\n            (void)cid;\n            if (!activeV[v]) continue;\n            mf.add_edge(h, Hcnt + v, INF_LL / 8);\n        }\n    }\n\n    mf.flow(S, T);\n    auto reach = mf.min_cut(S);\n\n    vector<char> ansH(Hcnt, false), ansV(Vcnt, false);\n    for (int h = 0; h < Hcnt; h++) if (activeH[h] && !reach[h]) ansH[h] = true;\n    for (int v = 0; v < Vcnt; v++) if (activeV[v] && reach[Hcnt + v]) ansV[v] = true;\n    return {ansH, ansV};\n}\n\nvector<Task> compressTasksByCell(vector<Task> tasks) {\n    vector<vector<Task>> buckets(Rcnt);\n    for (auto &t : tasks) buckets[t.cell].push_back(t);\n\n    vector<Task> out;\n    out.reserve(tasks.size());\n    for (int c = 0; c < Rcnt; c++) {\n        if (buckets[c].empty()) continue;\n        if (buckets[c].size() >= 2) out.push_back({0, -1, c});\n        else out.push_back(buckets[c][0]);\n    }\n\n    sort(out.begin(), out.end(), [&](const Task& a, const Task& b) {\n        if (a.cell != b.cell) return a.cell < b.cell;\n        if (a.type != b.type) return a.type < b.type;\n        return a.seg < b.seg;\n    });\n    return out;\n}\n\nvector<Task> buildTasksPaired(const vector<char>& selH, const vector<char>& selV) {\n    vector<int> matchH, matchV;\n    hopcroftKarp(selH, selV, adjHFull, matchH, matchV);\n\n    vector<Task> tasks;\n    for (int h = 0; h < Hcnt; h++) {\n        if (!selH[h]) continue;\n        if (matchH[h] != -1) {\n            int v = matchH[h];\n            int cid = -1;\n            for (auto [vv, ccid] : adjHFull[h]) {\n                if (vv == v) {\n                    cid = ccid;\n                    break;\n                }\n            }\n            if (cid != -1) tasks.push_back({0, -1, cid});\n        }\n    }\n    for (int h = 0; h < Hcnt; h++) if (selH[h] && matchH[h] == -1) tasks.push_back({1, h, bestCellH[h]});\n    for (int v = 0; v < Vcnt; v++) if (selV[v] && matchV[v] == -1) tasks.push_back({2, v, bestCellV[v]});\n    return compressTasksByCell(tasks);\n}\n\nvector<Task> buildTasksNoPair(const vector<char>& selH, const vector<char>& selV) {\n    vector<Task> tasks;\n    for (int h = 0; h < Hcnt; h++) if (selH[h]) tasks.push_back({1, h, bestCellH[h]});\n    for (int v = 0; v < Vcnt; v++) if (selV[v]) tasks.push_back({2, v, bestCellV[v]});\n    return compressTasksByCell(tasks);\n}\n\nvector<Task> buildTasksGreedyPair(const vector<char>& selH, const vector<char>& selV, ll penalty) {\n    struct E {\n        ll gain;\n        int h, v, cid;\n    };\n    vector<E> es;\n    for (int h = 0; h < Hcnt; h++) {\n        if (!selH[h]) continue;\n        ll baseH = distStart[bestCellH[h]];\n        for (auto [v, cid] : adjHFull[h]) {\n            if (!selV[v]) continue;\n            ll gain = baseH + (ll)distStart[bestCellV[v]] - (ll)distStart[cid] - penalty;\n            if (gain > 0) es.push_back({gain, h, v, cid});\n        }\n    }\n    sort(es.begin(), es.end(), [&](const E& a, const E& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (distStart[a.cid] != distStart[b.cid]) return distStart[a.cid] < distStart[b.cid];\n        return a.cid < b.cid;\n    });\n\n    vector<char> usedH(Hcnt, false), usedV(Vcnt, false);\n    vector<Task> tasks;\n    for (auto &e : es) {\n        if (usedH[e.h] || usedV[e.v]) continue;\n        usedH[e.h] = true;\n        usedV[e.v] = true;\n        tasks.push_back({0, -1, e.cid});\n    }\n    for (int h = 0; h < Hcnt; h++) if (selH[h] && !usedH[h]) tasks.push_back({1, h, bestCellH[h]});\n    for (int v = 0; v < Vcnt; v++) if (selV[v] && !usedV[v]) tasks.push_back({2, v, bestCellV[v]});\n    return compressTasksByCell(tasks);\n}\n\n// Exact optional weighted pairing via min-cost flow.\nvector<Task> buildTasksExactOptionalPair(const vector<char>& selH, const vector<char>& selV, ll penalty) {\n    vector<int> hs, vs;\n    vector<int> idxH(Hcnt, -1), idxV(Vcnt, -1);\n\n    for (int h = 0; h < Hcnt; h++) if (selH[h]) {\n        idxH[h] = (int)hs.size();\n        hs.push_back(h);\n    }\n    for (int v = 0; v < Vcnt; v++) if (selV[v]) {\n        idxV[v] = (int)vs.size();\n        vs.push_back(v);\n    }\n\n    int m = (int)hs.size(), n = (int)vs.size();\n    if (m == 0 && n == 0) return {};\n    if (m > 80 || n > 80) return buildTasksGreedyPair(selH, selV, penalty);\n\n    struct EdgeInfo {\n        int id;\n        int h, v, cid;\n    };\n    vector<EdgeInfo> edgeInfo;\n    ll maxBenefit = 0;\n\n    for (int ih = 0; ih < m; ih++) {\n        int h = hs[ih];\n        for (auto [v, cid] : adjHFull[h]) {\n            int iv = idxV[v];\n            if (iv == -1) continue;\n            ll benefit = (ll)distStart[bestCellH[h]] + (ll)distStart[bestCellV[v]] - (ll)distStart[cid] - penalty;\n            if (benefit > 0) maxBenefit = max(maxBenefit, benefit);\n        }\n    }\n\n    int S = 0;\n    int H0 = 1;\n    int V0 = H0 + m;\n    int T = V0 + n;\n    mcf_graph<int, ll> g(T + 1);\n\n    for (int ih = 0; ih < m; ih++) {\n        g.add_edge(S, H0 + ih, 1, 0);\n        g.add_edge(H0 + ih, T, 1, maxBenefit);\n    }\n    for (int iv = 0; iv < n; iv++) {\n        g.add_edge(V0 + iv, T, 1, 0);\n    }\n\n    for (int ih = 0; ih < m; ih++) {\n        int h = hs[ih];\n        for (auto [v, cid] : adjHFull[h]) {\n            int iv = idxV[v];\n            if (iv == -1) continue;\n            ll benefit = (ll)distStart[bestCellH[h]] + (ll)distStart[bestCellV[v]] - (ll)distStart[cid] - penalty;\n            if (benefit <= 0) continue;\n            int id = g.add_edge(H0 + ih, V0 + iv, 1, maxBenefit - benefit);\n            edgeInfo.push_back({id, h, v, cid});\n        }\n    }\n\n    g.flow(S, T, m);\n    auto es = g.edges();\n\n    vector<char> usedH(Hcnt, false), usedV(Vcnt, false);\n    vector<Task> tasks;\n    for (auto &e : edgeInfo) {\n        if (es[e.id].flow > 0) {\n            usedH[e.h] = true;\n            usedV[e.v] = true;\n            tasks.push_back({0, -1, e.cid});\n        }\n    }\n    for (int h : hs) if (!usedH[h]) tasks.push_back({1, h, bestCellH[h]});\n    for (int v : vs) if (!usedV[v]) tasks.push_back({2, v, bestCellV[v]});\n\n    return compressTasksByCell(tasks);\n}\n\nstring makeTaskSig(const vector<Task>& tasks) {\n    string s;\n    s.reserve(tasks.size() * 12);\n    for (auto &t : tasks) {\n        s += char('0' + t.type);\n        s += ':';\n        s += to_string(t.seg);\n        s += ':';\n        s += to_string(t.cell);\n        s += ';';\n    }\n    return s;\n}\n\nbool buildData(\n    const vector<Task>& tasks,\n    vector<int>& sourceCells,\n    vector<vector<ll>>& d0\n) {\n    if (elapsed_ms() > 2820) return false;\n    int M = (int)tasks.size() + 1;\n    sourceCells.assign(M, -1);\n    sourceCells[0] = sId;\n    for (int i = 0; i < (int)tasks.size(); i++) sourceCells[i + 1] = tasks[i].cell;\n\n    for (int i = 0; i < M; i++) ensureDijkstra(sourceCells[i]);\n\n    d0.assign(M, vector<ll>(M, 0));\n    for (int i = 0; i < M; i++) {\n        int ci = sourceCells[i];\n        for (int j = 0; j < M; j++) {\n            if (i == j) d0[i][j] = 0;\n            else d0[i][j] = (ll)distCache[ci][sourceCells[j]] + cellW[ci];\n        }\n    }\n    return true;\n}\n\nll routeCostMat(const vector<int>& route, const vector<vector<ll>>& d0) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) s += d0[route[i]][route[i + 1]];\n    return s;\n}\n\nll routeActualCost(const vector<int>& route, const vector<int>& sourceCells) {\n    ll s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distCache[sourceCells[route[i]]][sourceCells[route[i + 1]]];\n    }\n    return s;\n}\n\nvector<int> routeNearestNeighbor(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    vector<int> route;\n    route.reserve(M + 2);\n    route.push_back(0);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    int cur = 0;\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        ll bestD = INF_LL;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeNearestSeed(const vector<vector<ll>>& d0, int first) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n    if (first < 1 || first > M) return routeNearestNeighbor(d0);\n\n    vector<int> route;\n    route.reserve(M + 2);\n    vector<char> used(M + 1, false);\n    used[0] = true;\n    used[first] = true;\n    route.push_back(0);\n    route.push_back(first);\n    int cur = first;\n\n    for (int step = 1; step < M; step++) {\n        int best = -1;\n        ll bestD = INF_LL;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            if (d0[cur][p] < bestD) {\n                bestD = d0[cur][p];\n                best = p;\n            }\n        }\n        if (best == -1) break;\n        used[best] = true;\n        route.push_back(best);\n        cur = best;\n    }\n    route.push_back(0);\n    return route;\n}\n\nvector<int> routeCheapestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    used[0] = true;\n\n    int first = 1;\n    ll bestFirst = INF_LL;\n    for (int p = 1; p <= M; p++) {\n        ll val = d0[0][p] + d0[p][0];\n        if (val < bestFirst) {\n            bestFirst = val;\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        ll bestInc = INF_LL;\n        int bestP = -1, bestPos = -1;\n        for (int p = 1; p <= M; p++) {\n            if (used[p]) continue;\n            for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n                int a = route[pos], b = route[pos + 1];\n                ll inc = d0[a][p] + d0[p][b] - d0[a][b];\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestP = p;\n                    bestPos = pos;\n                }\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, bestP);\n        used[bestP] = true;\n    }\n    return route;\n}\n\nvector<int> routeFarthestInsertion(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    vector<char> used(M + 1, false);\n    int first = 1;\n    ll far = -1;\n    for (int p = 1; p <= M; p++) {\n        if (d0[0][p] > far) {\n            far = d0[0][p];\n            first = p;\n        }\n    }\n\n    vector<int> route = {0, first, 0};\n    used[first] = true;\n\n    for (int added = 1; added < M; added++) {\n        int pick = -1;\n        ll bestFar = -1;\n        for (int p = 1; p <= M; p++) if (!used[p]) {\n            ll mn = INF_LL;\n            for (int x : route) mn = min(mn, d0[x][p]);\n            if (mn > bestFar) {\n                bestFar = mn;\n                pick = p;\n            }\n        }\n\n        ll bestInc = INF_LL;\n        int bestPos = -1;\n        for (int pos = 0; pos + 1 < (int)route.size(); pos++) {\n            int a = route[pos], b = route[pos + 1];\n            ll inc = d0[a][pick] + d0[pick][b] - d0[a][b];\n            if (inc < bestInc) {\n                bestInc = inc;\n                bestPos = pos;\n            }\n        }\n        route.insert(route.begin() + bestPos + 1, pick);\n        used[pick] = true;\n    }\n\n    return route;\n}\n\nvoid improve2opt(vector<int>& route, const vector<vector<ll>>& d0) {\n    int M = (int)route.size() - 2;\n    int maxPass = (M <= 35 ? 4 : M <= 70 ? 2 : 1);\n    int L = (int)route.size();\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool improved = false;\n        for (int i = 1; i + 2 < L; i++) {\n            for (int j = i + 1; j + 1 < L; j++) {\n                ll oldv = d0[route[i - 1]][route[i]] + d0[route[j]][route[j + 1]];\n                ll newv = d0[route[i - 1]][route[j]] + d0[route[i]][route[j + 1]];\n                if (newv < oldv) {\n                    reverse(route.begin() + i, route.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n        if (!improved || elapsed_ms() > 2750) break;\n    }\n}\n\nbool improveRelocateOnce(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    for (int i = 1; i + 1 < L; i++) {\n        int a = route[i - 1], x = route[i], b = route[i + 1];\n        for (int j = 0; j + 1 < L; j++) {\n            if (j == i || j == i - 1) continue;\n            int c = route[j], d = route[j + 1];\n            ll oldv = d0[a][x] + d0[x][b] + d0[c][d];\n            ll newv = d0[a][b] + d0[c][x] + d0[x][d];\n            if (newv < oldv) {\n                int val = route[i];\n                route.erase(route.begin() + i);\n                if (j < i) route.insert(route.begin() + (j + 1), val);\n                else route.insert(route.begin() + j, val);\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nbool improveSwapOnce(vector<int>& route, const vector<vector<ll>>& d0) {\n    int L = (int)route.size();\n    for (int i = 1; i + 1 < L; i++) {\n        for (int j = i + 1; j + 1 < L; j++) {\n            ll oldv, newv;\n            int x = route[i], y = route[j];\n            if (j == i + 1) {\n                int a = route[i - 1], d = route[j + 1];\n                oldv = d0[a][x] + d0[x][y] + d0[y][d];\n                newv = d0[a][y] + d0[y][x] + d0[x][d];\n            } else {\n                int a = route[i - 1], b = route[i + 1];\n                int c = route[j - 1], d = route[j + 1];\n                oldv = d0[a][x] + d0[x][b] + d0[c][y] + d0[y][d];\n                newv = d0[a][y] + d0[y][b] + d0[c][x] + d0[x][d];\n            }\n            if (newv < oldv) {\n                swap(route[i], route[j]);\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nbool improveRelocateBlockOnce(vector<int>& route, const vector<vector<ll>>& d0, int len) {\n    int L = (int)route.size();\n    if (L - 2 <= len) return false;\n    ll curCost = routeCostMat(route, d0);\n\n    for (int i = 1; i + len - 1 <= L - 2; i++) {\n        if (elapsed_ms() > 2730) return false;\n\n        vector<int> block(route.begin() + i, route.begin() + i + len);\n        vector<int> rem = route;\n        rem.erase(rem.begin() + i, rem.begin() + i + len);\n\n        for (int pos = 0; pos + 1 < (int)rem.size(); pos++) {\n            vector<int> cand = rem;\n            cand.insert(cand.begin() + pos + 1, block.begin(), block.end());\n            if (cand == route) continue;\n            ll c = routeCostMat(cand, d0);\n            if (c < curCost) {\n                route.swap(cand);\n                return true;\n            }\n        }\n    }\n    return false;\n}\n\nvoid improveRoute(vector<int>& route, const vector<vector<ll>>& d0) {\n    int M = (int)route.size() - 2;\n    improve2opt(route, d0);\n\n    if (M <= 40 && elapsed_ms() < 2650) {\n        for (int iter = 0; iter < 6; iter++) {\n            bool imp = false;\n\n            if (improveRelocateOnce(route, d0)) {\n                imp = true;\n                improve2opt(route, d0);\n            }\n            if (improveSwapOnce(route, d0)) {\n                imp = true;\n                improve2opt(route, d0);\n            }\n\n            if (!imp && M <= 32 && elapsed_ms() < 2680) {\n                if (improveRelocateBlockOnce(route, d0, 2)) {\n                    imp = true;\n                    improve2opt(route, d0);\n                }\n            }\n            if (!imp && M <= 20 && elapsed_ms() < 2680) {\n                if (improveRelocateBlockOnce(route, d0, 3)) {\n                    imp = true;\n                    improve2opt(route, d0);\n                }\n            }\n\n            if (!imp || elapsed_ms() > 2750) break;\n        }\n    }\n}\n\nvector<int> exactRoute(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n    if (M == 1) return {0, 1, 0};\n\n    int S = 1 << M;\n    vector<vector<ll>> dp(S, vector<ll>(M, INF_LL));\n    vector<vector<short>> pre(S, vector<short>(M, -1));\n\n    for (int i = 0; i < M; i++) dp[1 << i][i] = d0[0][i + 1];\n\n    for (int mask = 1; mask < S; mask++) {\n        for (int i = 0; i < M; i++) {\n            if (!(mask & (1 << i))) continue;\n            ll cur = dp[mask][i];\n            if (cur >= INF_LL / 4) continue;\n            int rem = ((S - 1) ^ mask);\n            while (rem) {\n                int b = rem & -rem;\n                int j = __builtin_ctz(b);\n                int nmask = mask | b;\n                ll nd = cur + d0[i + 1][j + 1];\n                if (nd < dp[nmask][j]) {\n                    dp[nmask][j] = nd;\n                    pre[nmask][j] = (short)i;\n                }\n                rem ^= b;\n            }\n        }\n    }\n\n    int all = S - 1;\n    ll best = INF_LL;\n    int last = -1;\n    for (int i = 0; i < M; i++) {\n        ll val = dp[all][i] + d0[i + 1][0];\n        if (val < best) {\n            best = val;\n            last = i;\n        }\n    }\n\n    vector<int> ord;\n    int mask = all;\n    while (last != -1) {\n        ord.push_back(last + 1);\n        int pl = pre[mask][last];\n        mask ^= (1 << last);\n        last = pl;\n    }\n    reverse(ord.begin(), ord.end());\n\n    vector<int> route;\n    route.push_back(0);\n    for (int x : ord) route.push_back(x);\n    route.push_back(0);\n    return route;\n}\n\nvector<int> buildBestOrder(const vector<vector<ll>>& d0) {\n    int M = (int)d0.size() - 1;\n    if (M == 0) return {0, 0};\n\n    if (M <= 18 && elapsed_ms() < 120) return exactRoute(d0);\n    if (M <= 17 && elapsed_ms() < 300) return exactRoute(d0);\n    if (M <= 16 && elapsed_ms() < 700) return exactRoute(d0);\n    if (M <= 15 && elapsed_ms() < 1200) return exactRoute(d0);\n    if (M <= 14 && elapsed_ms() < 1850) return exactRoute(d0);\n    if (M <= 13 && elapsed_ms() < 2350) return exactRoute(d0);\n\n    vector<vector<int>> cands;\n    cands.push_back(routeCheapestInsertion(d0));\n    cands.push_back(routeNearestNeighbor(d0));\n    if (M <= 60) cands.push_back(routeFarthestInsertion(d0));\n\n    if (M >= 2 && M <= 70) {\n        vector<pair<ll,int>> ord;\n        ord.reserve(M);\n        for (int p = 1; p <= M; p++) ord.push_back({d0[0][p], p});\n        sort(ord.begin(), ord.end(), greater<pair<ll,int>>());\n        cands.push_back(routeNearestSeed(d0, ord[0].second));\n        if (M >= 3) cands.push_back(routeNearestSeed(d0, ord[1].second));\n        if (M >= 4) cands.push_back(routeNearestSeed(d0, ord[2].second));\n    }\n\n    ll best = INF_LL;\n    vector<int> bestRoute;\n\n    for (auto route : cands) {\n        improveRoute(route, d0);\n        ll c = routeCostMat(route, d0);\n        if (c < best) {\n            best = c;\n            bestRoute = move(route);\n        }\n        if (elapsed_ms() > 2780) break;\n    }\n    return bestRoute;\n}\n\nbool refineTaskCells(vector<Task>& tasks, const vector<int>& route, const vector<int>& sourceCells) {\n    int M = (int)tasks.size();\n    vector<int> pos(M + 1, -1);\n    for (int i = 0; i < (int)route.size(); i++) pos[route[i]] = i;\n\n    bool changed = false;\n    for (int ti = 0; ti < M; ti++) {\n        if (tasks[ti].type == 0) continue;\n        int idx = ti + 1;\n        int p = pos[idx];\n        if (p <= 0 || p + 1 >= (int)route.size()) continue;\n\n        int prevCell = sourceCells[route[p - 1]];\n        int nextCell = sourceCells[route[p + 1]];\n        const vector<int>& candCells =\n            (tasks[ti].type == 1 ? cellsH[tasks[ti].seg] : cellsV[tasks[ti].seg]);\n\n        ll bestVal = INF_LL;\n        int bestCid = tasks[ti].cell;\n        for (int cid : candCells) {\n            ll val = (ll)distCache[prevCell][cid]\n                   + (ll)distCache[nextCell][cid]\n                   + cellW[nextCell] - cellW[cid];\n            if (val < bestVal) {\n                bestVal = val;\n                bestCid = cid;\n            } else if (val == bestVal) {\n                if (distStart[cid] < distStart[bestCid]) bestCid = cid;\n            }\n        }\n        if (bestCid != tasks[ti].cell) {\n            tasks[ti].cell = bestCid;\n            changed = true;\n        }\n    }\n    return changed;\n}\n\nstring reconstructPath(const vector<int>& route, const vector<int>& sourceCells) {\n    string out;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        int src = sourceCells[route[i]];\n        int dst = sourceCells[route[i + 1]];\n        if (src == dst) continue;\n\n        vector<int> rev;\n        int cur = dst;\n        while (cur != src) {\n            int p = parentCache[src][cur];\n            if (p == -1) return \"\";\n            rev.push_back(cur);\n            cur = p;\n        }\n        reverse(rev.begin(), rev.end());\n\n        int prev = src;\n        for (int x : rev) {\n            char c = dirChar(prev, x);\n            if (c == '?') return \"\";\n            out.push_back(c);\n            prev = x;\n        }\n    }\n    return out;\n}\n\nstring pruneOneLoop(const string& path) {\n    if (path.empty()) return path;\n\n    int L = (int)path.size();\n    vector<int> pos(L + 1);\n    pos[0] = sId;\n    int cur = sId;\n    for (int i = 0; i < L; i++) {\n        int ni = rr[cur], nj = cc[cur];\n        char ch = path[i];\n        if (ch == 'U') ni--;\n        else if (ch == 'D') ni++;\n        else if (ch == 'L') nj--;\n        else if (ch == 'R') nj++;\n        else return path;\n        if (ni < 0 || ni >= N || nj < 0 || nj >= N) return path;\n        int nxt = idg[ni][nj];\n        if (nxt == -1) return path;\n        cur = nxt;\n        pos[i + 1] = cur;\n    }\n\n    vector<int> cntH(Hcnt, 0), cntV(Vcnt, 0);\n    for (int x : pos) {\n        cntH[hid[x]]++;\n        cntV[vid[x]]++;\n    }\n\n    vector<int> last(Rcnt, -1);\n    vector<int> tmpH(Hcnt, 0), tmpV(Vcnt, 0);\n    vector<int> touchedH, touchedV;\n\n    for (int r = 0; r <= L; r++) {\n        int cell = pos[r];\n        int l = last[cell];\n        if (l != -1 && r > l) {\n            touchedH.clear();\n            touchedV.clear();\n            for (int k = l + 1; k <= r; k++) {\n                int c = pos[k];\n                int h = hid[c], v = vid[c];\n                if (tmpH[h]++ == 0) touchedH.push_back(h);\n                if (tmpV[v]++ == 0) touchedV.push_back(v);\n            }\n\n            bool ok = true;\n            for (int h : touchedH) {\n                if (cntH[h] - tmpH[h] == 0) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) {\n                for (int v : touchedV) {\n                    if (cntV[v] - tmpV[v] == 0) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n\n            for (int h : touchedH) tmpH[h] = 0;\n            for (int v : touchedV) tmpV[v] = 0;\n\n            if (ok) {\n                string res;\n                res.reserve(path.size() - (r - l));\n                res.append(path.begin(), path.begin() + l);\n                res.append(path.begin() + r, path.end());\n                return res;\n            }\n        }\n        last[cell] = r;\n    }\n    return path;\n}\n\nstring pruneLoops(string path) {\n    for (int pass = 0; pass < 4; pass++) {\n        if (elapsed_ms() > 2890) break;\n        string np = pruneOneLoop(path);\n        if (np.size() == path.size()) break;\n        auto [ok, c] = validateAndCost(np);\n        (void)c;\n        if (!ok) break;\n        path = move(np);\n    }\n    return path;\n}\n\nvoid tryDeleteWaypointBlock(\n    vector<int>& route,\n    const vector<int>& sourceCells,\n    string& curPath,\n    ll& curCost,\n    int blockLen,\n    int maxPass\n) {\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool improved = false;\n        for (int i = 1; i + blockLen < (int)route.size(); i++) {\n            if (elapsed_ms() > 2830) return;\n            if (i + blockLen >= (int)route.size() - 1) break;\n\n            int a = sourceCells[route[i - 1]];\n            int c = sourceCells[route[i + blockLen]];\n\n            ll oldPart = 0;\n            for (int k = i - 1; k < i + blockLen; k++) {\n                int x = sourceCells[route[k]];\n                int y = sourceCells[route[k + 1]];\n                oldPart += (ll)distCache[x][y];\n            }\n            ll newPart = (ll)distCache[a][c];\n            if (newPart >= oldPart) continue;\n\n            vector<int> candRoute = route;\n            candRoute.erase(candRoute.begin() + i, candRoute.begin() + i + blockLen);\n\n            string candPath = reconstructPath(candRoute, sourceCells);\n            if (candPath.empty()) continue;\n\n            auto [ok, cost] = validateAndCost(candPath);\n            if (ok && cost < curCost) {\n                route.swap(candRoute);\n                curPath.swap(candPath);\n                curCost = cost;\n                improved = true;\n                break;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvoid deleteRedundantWaypoints(vector<int>& route, const vector<int>& sourceCells, string& curPath, ll& curCost) {\n    int M = (int)route.size() - 2;\n    if (M > 35) return;\n    if (elapsed_ms() > 2700) return;\n\n    tryDeleteWaypointBlock(route, sourceCells, curPath, curCost, 1, 2);\n\n    M = (int)route.size() - 2;\n    if (M <= 28 && elapsed_ms() <= 2790) {\n        tryDeleteWaypointBlock(route, sourceCells, curPath, curCost, 2, 1);\n    }\n    M = (int)route.size() - 2;\n    if (M <= 18 && elapsed_ms() <= 2790) {\n        tryDeleteWaypointBlock(route, sourceCells, curPath, curCost, 3, 1);\n    }\n}\n\nCandidateResult solveCandidate(vector<Task> tasks) {\n    CandidateResult res;\n    tasks = compressTasksByCell(tasks);\n\n    if ((int)tasks.size() > 90) return res;\n    if (elapsed_ms() > 2810) return res;\n\n    if (tasks.empty()) {\n        auto [ok, c] = validateAndCost(\"\");\n        if (ok) {\n            res.valid = true;\n            res.cost = c;\n            res.path = \"\";\n        }\n        return res;\n    }\n\n    vector<int> sourceCells;\n    vector<vector<ll>> d0;\n\n    if (!buildData(tasks, sourceCells, d0)) return res;\n    vector<int> route = buildBestOrder(d0);\n    ll bestRouteCost = routeActualCost(route, sourceCells);\n\n    if ((int)tasks.size() <= 70) {\n        int maxRefine = ((int)tasks.size() <= 50 ? 3 : 2);\n        for (int it = 0; it < maxRefine && elapsed_ms() < 2520; it++) {\n            vector<Task> tasks2 = tasks;\n            if (!refineTaskCells(tasks2, route, sourceCells)) break;\n            tasks2 = compressTasksByCell(tasks2);\n            if ((int)tasks2.size() > 90) break;\n\n            vector<int> sourceCells2;\n            vector<vector<ll>> d02;\n            if (!buildData(tasks2, sourceCells2, d02)) break;\n\n            auto route2 = buildBestOrder(d02);\n            ll cost2 = routeActualCost(route2, sourceCells2);\n            if (cost2 < bestRouteCost) {\n                tasks = move(tasks2);\n                sourceCells = move(sourceCells2);\n                d0 = move(d02);\n                route = move(route2);\n                bestRouteCost = cost2;\n            } else {\n                break;\n            }\n        }\n    }\n\n    string path = reconstructPath(route, sourceCells);\n    auto [ok, c] = validateAndCost(path);\n    if (!ok) return res;\n\n    deleteRedundantWaypoints(route, sourceCells, path, c);\n\n    if (!path.empty() && elapsed_ms() < 2790) {\n        int passes = ((int)route.size() - 2 <= 24 ? 2 : 1);\n        for (int p = 0; p < passes; p++) {\n            string p2 = pruneOneLoop(path);\n            if (p2.size() == path.size()) break;\n            auto [ok2, c2] = validateAndCost(p2);\n            if (ok2 && c2 < c) {\n                path = move(p2);\n                c = c2;\n            } else break;\n        }\n    }\n\n    res.valid = true;\n    res.cost = c;\n    res.path = move(path);\n    return res;\n}\n\nstring buildFallbackDFSRoute() {\n    vector<char> vis(Rcnt, false);\n    string out;\n\n    vector<int> it(Rcnt, 0);\n    vector<int> st;\n    st.push_back(sId);\n    vis[sId] = true;\n\n    while (!st.empty()) {\n        int u = st.back();\n        if (it[u] == (int)nbrs[u].size()) {\n            st.pop_back();\n            if (!st.empty()) {\n                int p = st.back();\n                out.push_back(dirChar(u, p));\n            }\n            continue;\n        }\n        int v = nbrs[u][it[u]++];\n        if (vis[v]) continue;\n        vis[v] = true;\n        out.push_back(dirChar(u, v));\n        st.push_back(v);\n    }\n    return out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    globalStart = chrono::steady_clock::now();\n\n    cin >> N >> si >> sj;\n    gridc.resize(N);\n    for (int i = 0; i < N; i++) cin >> gridc[i];\n\n    idg.assign(N, vector<int>(N, -1));\n    rr.clear();\n    cc.clear();\n    cellW.clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (gridc[i][j] != '#') {\n                idg[i][j] = (int)rr.size();\n                rr.push_back(i);\n                cc.push_back(j);\n                cellW.push_back(gridc[i][j] - '0');\n            }\n        }\n    }\n\n    Rcnt = (int)rr.size();\n    sId = idg[si][sj];\n\n    nbrs.assign(Rcnt, {});\n    const int di[4] = {-1, 1, 0, 0};\n    const int dj[4] = {0, 0, -1, 1};\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int i = rr[cid], j = cc[cid];\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) {\n                int nid = idg[ni][nj];\n                if (nid != -1) nbrs[cid].push_back(nid);\n            }\n        }\n    }\n    for (int u = 0; u < Rcnt; u++) {\n        sort(nbrs[u].begin(), nbrs[u].end(), [&](int a, int b) {\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    hid.assign(Rcnt, -1);\n    vid.assign(Rcnt, -1);\n    cellsH.clear();\n    cellsV.clear();\n\n    Hcnt = 0;\n    for (int i = 0; i < N; i++) {\n        int j = 0;\n        while (j < N) {\n            if (idg[i][j] == -1) {\n                j++;\n                continue;\n            }\n            int h = Hcnt++;\n            cellsH.push_back({});\n            while (j < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                hid[cid] = h;\n                cellsH[h].push_back(cid);\n                j++;\n            }\n        }\n    }\n\n    Vcnt = 0;\n    for (int j = 0; j < N; j++) {\n        int i = 0;\n        while (i < N) {\n            if (idg[i][j] == -1) {\n                i++;\n                continue;\n            }\n            int v = Vcnt++;\n            cellsV.push_back({});\n            while (i < N && idg[i][j] != -1) {\n                int cid = idg[i][j];\n                vid[cid] = v;\n                cellsV[v].push_back(cid);\n                i++;\n            }\n        }\n    }\n\n    adjHFull.assign(Hcnt, {});\n    for (int cid = 0; cid < Rcnt; cid++) {\n        adjHFull[hid[cid]].push_back({vid[cid], cid});\n    }\n\n    dijReady.assign(Rcnt, false);\n    distCache.assign(Rcnt, {});\n    parentCache.assign(Rcnt, {});\n    ensureDijkstra(sId);\n    distStart = distCache[sId];\n\n    bestCellH.assign(Hcnt, -1);\n    bestCellV.assign(Vcnt, -1);\n\n    auto betterCell = [&](int a, int b) {\n        if (a == -1) return true;\n        if (distStart[b] != distStart[a]) return distStart[b] < distStart[a];\n        if (cellW[b] != cellW[a]) return cellW[b] < cellW[a];\n        if (rr[b] != rr[a]) return rr[b] < rr[a];\n        return cc[b] < cc[a];\n    };\n\n    for (int h = 0; h < Hcnt; h++) {\n        for (int cid : cellsH[h]) {\n            if (bestCellH[h] == -1 || betterCell(bestCellH[h], cid)) bestCellH[h] = cid;\n        }\n    }\n    for (int v = 0; v < Vcnt; v++) {\n        for (int cid : cellsV[v]) {\n            if (bestCellV[v] == -1 || betterCell(bestCellV[v], cid)) bestCellV[v] = cid;\n        }\n    }\n\n    sH = hid[sId];\n    sV = vid[sId];\n\n    activeH.assign(Hcnt, false);\n    activeV.assign(Vcnt, false);\n    adjHRes.assign(Hcnt, {});\n    bool anyResidual = false;\n    for (int cid = 0; cid < Rcnt; cid++) {\n        int h = hid[cid], v = vid[cid];\n        if (h == sH || v == sV) continue;\n        activeH[h] = true;\n        activeV[v] = true;\n        adjHRes[h].push_back({v, cid});\n        anyResidual = true;\n    }\n\n    if (!anyResidual) {\n        cout << '\\n';\n        return 0;\n    }\n\n    vector<ll> segCostH(Hcnt, 0), segCostV(Vcnt, 0);\n    ll sumSeg = 0;\n    int cntSeg = 0;\n    for (int h = 0; h < Hcnt; h++) if (activeH[h]) {\n        segCostH[h] = distStart[bestCellH[h]];\n        sumSeg += segCostH[h];\n        cntSeg++;\n    }\n    for (int v = 0; v < Vcnt; v++) if (activeV[v]) {\n        segCostV[v] = distStart[bestCellV[v]];\n        sumSeg += segCostV[v];\n        cntSeg++;\n    }\n    ll avgSeg = max(1LL, cntSeg ? sumSeg / cntSeg : 1LL);\n\n    auto pairScore = [&](int cid) -> ll {\n        return segCostH[hid[cid]] + segCostV[vid[cid]] - distStart[cid];\n    };\n\n    for (int h = 0; h < Hcnt; h++) {\n        sort(adjHFull[h].begin(), adjHFull[h].end(), [&](auto A, auto B) {\n            ll sa = pairScore(A.second), sb = pairScore(B.second);\n            if (sa != sb) return sa > sb;\n            int a = A.second, b = B.second;\n            if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n        sort(adjHRes[h].begin(), adjHRes[h].end(), [&](auto A, auto B) {\n            ll sa = pairScore(A.second), sb = pairScore(B.second);\n            if (sa != sb) return sa > sb;\n            int a = A.second, b = B.second;\n            if (distStart[a] != distStart[b]) return distStart[a] < distStart[b];\n            if (cellW[a] != cellW[b]) return cellW[a] < cellW[b];\n            if (rr[a] != rr[b]) return rr[a] < rr[b];\n            return cc[a] < cc[b];\n        });\n    }\n\n    string bestPath = buildFallbackDFSRoute();\n    auto [fbok, fbcost] = validateAndCost(bestPath);\n    if (!fbok) {\n        bestPath = \"\";\n        fbcost = INF_LL;\n    }\n    ll bestCost = fbcost;\n\n    vector<pair<vector<char>, vector<char>>> covers;\n    unordered_set<string> seenCover;\n\n    auto addCover = [&](const vector<char>& selH, const vector<char>& selV) {\n        string sig;\n        sig.reserve(Hcnt + Vcnt);\n        for (int h = 0; h < Hcnt; h++) sig.push_back(selH[h] ? '1' : '0');\n        for (int v = 0; v < Vcnt; v++) sig.push_back(selV[v] ? '1' : '0');\n        if (seenCover.insert(sig).second) covers.push_back({selH, selV});\n    };\n\n    auto mvc = buildCanonicalMVC();\n    addCover(mvc.first, mvc.second);\n\n    ll base = sumSeg + 1;\n\n    vector<ll> wH1(Hcnt, 0), wV1(Vcnt, 0);\n    vector<ll> wH2(Hcnt, 0), wV2(Vcnt, 0);\n    vector<ll> wH3(Hcnt, 0), wV3(Vcnt, 0);\n    vector<ll> wH4(Hcnt, 0), wV4(Vcnt, 0);\n    vector<ll> wH5(Hcnt, 0), wV5(Vcnt, 0);\n    vector<ll> wH6(Hcnt, 0), wV6(Vcnt, 0);\n\n    for (int h = 0; h < Hcnt; h++) if (activeH[h]) {\n        wH1[h] = base + segCostH[h];\n        wH2[h] = 1 + segCostH[h];\n        wH3[h] = avgSeg + segCostH[h];\n        wH4[h] = max(1LL, avgSeg / 2) + segCostH[h];\n        wH5[h] = max(1LL, avgSeg * 2) + segCostH[h];\n        wH6[h] = max(1LL, avgSeg / 4) + segCostH[h];\n    }\n    for (int v = 0; v < Vcnt; v++) if (activeV[v]) {\n        wV1[v] = base + segCostV[v];\n        wV2[v] = 1 + segCostV[v];\n        wV3[v] = avgSeg + segCostV[v];\n        wV4[v] = max(1LL, avgSeg / 2) + segCostV[v];\n        wV5[v] = max(1LL, avgSeg * 2) + segCostV[v];\n        wV6[v] = max(1LL, avgSeg / 4) + segCostV[v];\n    }\n\n    auto cv1 = buildWeightedVC(wH1, wV1);\n    auto cv2 = buildWeightedVC(wH2, wV2);\n    auto cv3 = buildWeightedVC(wH3, wV3);\n    auto cv4 = buildWeightedVC(wH4, wV4);\n    auto cv5 = buildWeightedVC(wH5, wV5);\n    auto cv6 = buildWeightedVC(wH6, wV6);\n    addCover(cv1.first, cv1.second);\n    addCover(cv2.first, cv2.second);\n    addCover(cv3.first, cv3.second);\n    addCover(cv4.first, cv4.second);\n    addCover(cv5.first, cv5.second);\n    addCover(cv6.first, cv6.second);\n\n    {\n        vector<char> allH = activeH, allV(Vcnt, false);\n        addCover(allH, allV);\n    }\n    {\n        vector<char> allH(Hcnt, false), allV = activeV;\n        addCover(allH, allV);\n    }\n\n    struct CoverEntry {\n        vector<char> selH, selV;\n        int cnt;\n        ll est;\n    };\n    vector<CoverEntry> coverList;\n    for (auto &cv : covers) {\n        int cnt = 0;\n        ll est = 0;\n        for (int h = 0; h < Hcnt; h++) if (cv.first[h]) {\n            cnt++;\n            est += segCostH[h];\n        }\n        for (int v = 0; v < Vcnt; v++) if (cv.second[v]) {\n            cnt++;\n            est += segCostV[v];\n        }\n        coverList.push_back({cv.first, cv.second, cnt, est});\n    }\n    sort(coverList.begin(), coverList.end(), [&](const CoverEntry& A, const CoverEntry& B) {\n        if (A.cnt != B.cnt) return A.cnt < B.cnt;\n        return A.est < B.est;\n    });\n\n    struct CandEntry {\n        vector<Task> tasks;\n        int kind;\n        int pri;\n        ll est;\n    };\n\n    vector<CandEntry> candidates;\n    unordered_set<string> seenTask;\n\n    auto estimateTasks = [&](const vector<Task>& tasks) {\n        ll s = 0;\n        for (auto &t : tasks) s += distStart[t.cell];\n        s += (ll)tasks.size() * max(1LL, avgSeg / 4);\n        return s;\n    };\n\n    auto addTasks = [&](vector<Task> tasks, int kind, int pri) {\n        tasks = compressTasksByCell(tasks);\n        if ((int)tasks.size() > 90) return;\n        string sig = makeTaskSig(tasks);\n        if (seenTask.insert(sig).second) {\n            ll est = estimateTasks(tasks);\n            candidates.push_back({move(tasks), kind, pri, est});\n        }\n    };\n\n    ll greedyPenaltyNeg = -max(1LL, avgSeg / 4);\n    ll greedyPenalty0   = 0;\n    ll greedyPenalty1   = max(1LL, avgSeg / 5);\n    ll greedyPenalty2   = max(1LL, avgSeg / 2);\n    ll greedyPenalty3   = max(1LL, avgSeg);\n\n    ll exactPenaltyMax  = -1000000LL;            // maximize #pairs first, then benefit\n    ll exactPenalty0    = 0;\n    ll exactPenalty1    = max(1LL, avgSeg / 4);\n\n    for (int i = 0; i < (int)coverList.size(); i++) {\n        auto &cv = coverList[i];\n\n        addTasks(buildTasksPaired(cv.selH, cv.selV), 0, 10 + i);\n\n        if (i < 3) {\n            auto exMax = buildTasksExactOptionalPair(cv.selH, cv.selV, exactPenaltyMax);\n            if ((int)exMax.size() <= 80) addTasks(move(exMax), 1, 14 + i);\n\n            auto ex0 = buildTasksExactOptionalPair(cv.selH, cv.selV, exactPenalty0);\n            if ((int)ex0.size() <= 80) addTasks(move(ex0), 2, 20 + i);\n        }\n        if (i < 2) {\n            auto ex1 = buildTasksExactOptionalPair(cv.selH, cv.selV, exactPenalty1);\n            if ((int)ex1.size() <= 80) addTasks(move(ex1), 3, 26 + i);\n        }\n\n        if (i < 4) {\n            auto np = buildTasksNoPair(cv.selH, cv.selV);\n            if ((int)np.size() <= 65) addTasks(move(np), 7, 42 + i);\n        }\n\n        if (i < 3) {\n            auto gpNeg = buildTasksGreedyPair(cv.selH, cv.selV, greedyPenaltyNeg);\n            if ((int)gpNeg.size() <= 80) addTasks(move(gpNeg), 4, 30 + i);\n\n            auto gp0 = buildTasksGreedyPair(cv.selH, cv.selV, greedyPenalty0);\n            if ((int)gp0.size() <= 80) addTasks(move(gp0), 5, 34 + i);\n\n            auto gp1 = buildTasksGreedyPair(cv.selH, cv.selV, greedyPenalty1);\n            if ((int)gp1.size() <= 80) addTasks(move(gp1), 6, 38 + i);\n        }\n\n        if (i < 2) {\n            auto gp2 = buildTasksGreedyPair(cv.selH, cv.selV, greedyPenalty2);\n            if ((int)gp2.size() <= 80) addTasks(move(gp2), 8, 54 + i);\n\n            auto gp3 = buildTasksGreedyPair(cv.selH, cv.selV, greedyPenalty3);\n            if ((int)gp3.size() <= 80) addTasks(move(gp3), 9, 62 + i);\n        }\n    }\n\n    vector<int> kindLimit = {\n        5, // paired HK\n        4, // exact weighted max-cardinality\n        4, // exact optional 0\n        3, // exact optional avg/4\n        4, // greedy neg\n        4, // greedy 0\n        4, // greedy avg/5\n        5, // no-pair\n        3, // greedy avg/2\n        2  // greedy avg\n    };\n\n    vector<CandEntry> filtered;\n    for (int kind = 0; kind <= 9; kind++) {\n        vector<CandEntry> tmp;\n        for (auto &ce : candidates) if (ce.kind == kind) tmp.push_back(ce);\n        sort(tmp.begin(), tmp.end(), [&](const CandEntry& A, const CandEntry& B) {\n            if (A.pri != B.pri) return A.pri < B.pri;\n            if (A.est != B.est) return A.est < B.est;\n            return A.tasks.size() < B.tasks.size();\n        });\n        int lim = min<int>(kindLimit[kind], tmp.size());\n        for (int i = 0; i < lim; i++) filtered.push_back(move(tmp[i]));\n    }\n\n    sort(filtered.begin(), filtered.end(), [&](const CandEntry& A, const CandEntry& B) {\n        if (A.pri != B.pri) return A.pri < B.pri;\n        if (A.est != B.est) return A.est < B.est;\n        return A.tasks.size() < B.tasks.size();\n    });\n\n    if ((int)filtered.size() > 28) filtered.resize(28);\n\n    for (auto &ce : filtered) {\n        if (elapsed_ms() > 2770) break;\n        CandidateResult cr = solveCandidate(ce.tasks);\n        if (cr.valid && cr.cost < bestCost) {\n            bestCost = cr.cost;\n            bestPath = move(cr.path);\n        }\n    }\n\n    if (!bestPath.empty() && elapsed_ms() < 2890) {\n        string pruned = pruneLoops(bestPath);\n        auto [okp, cp] = validateAndCost(pruned);\n        if (okp && cp < bestCost) {\n            bestCost = cp;\n            bestPath = move(pruned);\n        }\n    }\n\n    cout << bestPath << '\\n';\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int MAXN = 1000;\nstatic constexpr ll INF64 = (1LL << 62);\nstatic constexpr ll DUMMY_UTILITY = -4'000'000'000'000LL;\n\nstruct Observation {\n    int task;\n    int dur;\n};\n\nstruct Member {\n    int current_task = -1;\n    int start_day = -1;\n    vector<Observation> obs;\n    vector<int> est;\n    bool busy() const { return current_task != -1; }\n};\n\nstruct Solver {\n    int N, M, K, R;\n    vector<vector<int>> req;\n    vector<vector<int>> g;\n    vector<int> indeg_rem;\n    vector<int> state; // 0:not started, 1:in progress, 2:done\n    vector<Member> members;\n\n    vector<int> maxD;\n    vector<double> prior_cap;\n    vector<int> prior_int;\n    vector<double> rank_skill;\n    vector<double> easy_skill;\n\n    vector<int> desc_count;\n    vector<double> avg_proc;\n    vector<double> up_rank;\n    vector<double> base_priority_static;\n    vector<double> global_easy_dur;\n\n    int completed_tasks = 0;\n\n    static double expected_duration_from_w(double w) {\n        if (w <= 0.0) return 1.0;\n        static const double E[5] = {\n            1.0,\n            13.0 / 7.0,\n            17.0 / 7.0,\n            22.0 / 7.0,\n            4.0\n        };\n        if (w < 4.0) {\n            int a = (int)floor(w);\n            double f = w - a;\n            return E[a] * (1.0 - f) + E[a + 1] * f;\n        }\n        return w;\n    }\n\n    double predict_duration_with_skill(const vector<double>& skill, int task) const {\n        double w = 0.0;\n        for (int k = 0; k < K; k++) {\n            double diff = (double)req[task][k] - skill[k];\n            if (diff > 0) w += diff;\n        }\n        return expected_duration_from_w(w);\n    }\n\n    static pair<int,int> duration_interval(int t) {\n        if (t <= 1) return {0, 4};\n        return {max(1, t - 3), t + 3};\n    }\n\n    void read_input() {\n        cin >> N >> M >> K >> R;\n        req.assign(N, vector<int>(K));\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) cin >> req[i][k];\n        }\n        g.assign(N, {});\n        indeg_rem.assign(N, 0);\n        for (int i = 0; i < R; i++) {\n            int u, v;\n            cin >> u >> v;\n            --u; --v;\n            g[u].push_back(v);\n            indeg_rem[v]++;\n        }\n        state.assign(N, 0);\n        members.assign(M, Member{});\n    }\n\n    void preprocess() {\n        maxD.assign(K, 0);\n        vector<double> meanD(K, 0.0);\n        for (int i = 0; i < N; i++) {\n            for (int k = 0; k < K; k++) {\n                maxD[k] = max(maxD[k], req[i][k]);\n                meanD[k] += req[i][k];\n            }\n        }\n        for (int k = 0; k < K; k++) meanD[k] /= N;\n\n        prior_cap.assign(K, 0.0);\n        prior_int.assign(K, 0);\n        rank_skill.assign(K, 0.0);\n        easy_skill.assign(K, 0.0);\n\n        for (int k = 0; k < K; k++) {\n            double p = 1.6 * meanD[k];\n            p = min<double>(p, maxD[k]);\n            if (p < 0) p = 0;\n            prior_cap[k] = p;\n            prior_int[k] = (int)llround(p);\n            prior_int[k] = max(0, min(prior_int[k], maxD[k]));\n            rank_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.75);\n            easy_skill[k] = min<double>(maxD[k], prior_cap[k] * 0.80);\n        }\n\n        for (int j = 0; j < M; j++) {\n            members[j].est = prior_int;\n        }\n\n        // Exact descendant counts with bitset.\n        vector<bitset<MAXN>> reach(N);\n        desc_count.assign(N, 0);\n        for (int i = N - 1; i >= 0; i--) {\n            bitset<MAXN> bs;\n            for (int to : g[i]) {\n                bs |= reach[to];\n                bs.set(to);\n            }\n            reach[i] = bs;\n            desc_count[i] = (int)bs.count();\n        }\n\n        avg_proc.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            avg_proc[i] = predict_duration_with_skill(rank_skill, i);\n        }\n\n        up_rank.assign(N, 0.0);\n        for (int i = N - 1; i >= 0; i--) {\n            double mx = 0.0;\n            for (int to : g[i]) mx = max(mx, up_rank[to]);\n            up_rank[i] = avg_proc[i] + mx;\n        }\n\n        base_priority_static.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            base_priority_static[i] = up_rank[i] + 0.03 * desc_count[i];\n        }\n\n        global_easy_dur.assign(N, 0.0);\n        for (int i = 0; i < N; i++) {\n            global_easy_dur[i] = predict_duration_with_skill(easy_skill, i);\n        }\n    }\n\n    void reestimate_member(int j) {\n        auto& mem = members[j];\n        int nobs = (int)mem.obs.size();\n        if (nobs == 0) {\n            mem.est = prior_int;\n            return;\n        }\n        if ((int)mem.est.size() != K) mem.est = prior_int;\n\n        vector<int> s = mem.est;\n        for (int k = 0; k < K; k++) {\n            s[k] = max(0, min(s[k], maxD[k]));\n        }\n\n        vector<int> task_id(nobs), L(nobs), U(nobs);\n        for (int i = 0; i < nobs; i++) {\n            task_id[i] = mem.obs[i].task;\n            auto [l, u] = duration_interval(mem.obs[i].dur);\n            L[i] = l;\n            U[i] = u;\n        }\n\n        vector<int> pred(nobs, 0);\n        for (int i = 0; i < nobs; i++) {\n            int t = task_id[i];\n            int w = 0;\n            for (int k = 0; k < K; k++) {\n                w += max(0, req[t][k] - s[k]);\n            }\n            pred[i] = w;\n        }\n\n        int passes = (nobs < 8 ? 3 : 2);\n        double reg = 10.0 / (nobs + 3.0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            for (int k = 0; k < K; k++) {\n                int old = s[k];\n                int lim = maxD[k];\n\n                vector<int> dk(nobs), oldPart(nobs);\n                for (int i = 0; i < nobs; i++) {\n                    int dkk = req[task_id[i]][k];\n                    dk[i] = dkk;\n                    oldPart[i] = max(0, dkk - old);\n                }\n\n                double bestObj = 1e100;\n                int bestX = old;\n\n                for (int x = 0; x <= lim; x++) {\n                    double obj = reg * (x - prior_int[k]) * (x - prior_int[k]);\n                    for (int i = 0; i < nobs; i++) {\n                        int w = pred[i] - oldPart[i] + max(0, dk[i] - x);\n                        if (w < L[i]) {\n                            double d = (double)(L[i] - w);\n                            obj += d * d;\n                        } else if (w > U[i]) {\n                            double d = (double)(w - U[i]);\n                            obj += d * d;\n                        }\n                    }\n                    if (obj < bestObj) {\n                        bestObj = obj;\n                        bestX = x;\n                    }\n                }\n\n                if (bestX != old) {\n                    for (int i = 0; i < nobs; i++) {\n                        pred[i] = pred[i] - oldPart[i] + max(0, dk[i] - bestX);\n                    }\n                    s[k] = bestX;\n                }\n            }\n        }\n\n        mem.est = s;\n    }\n\n    vector<int> hungarian_min(const vector<vector<ll>>& cost) {\n        int n = (int)cost.size();\n        int m = (int)cost[0].size();\n        // Requires n <= m\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF64);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF64;\n                for (int j = 1; j <= m; j++) {\n                    if (used[j]) continue;\n                    ll cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0 != 0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    vector<pair<int,int>> choose_assignments(int day) {\n        vector<int> free_members, ready_tasks;\n        for (int j = 0; j < M; j++) if (!members[j].busy()) free_members.push_back(j);\n        for (int i = 0; i < N; i++) if (state[i] == 0 && indeg_rem[i] == 0) ready_tasks.push_back(i);\n\n        if (free_members.empty() || ready_tasks.empty()) return {};\n\n        vector<vector<double>> eff_skill(M, vector<double>(K, 0.0));\n        for (int j = 0; j < M; j++) {\n            double conf = (double)members[j].obs.size() / (members[j].obs.size() + 5.0);\n            for (int k = 0; k < K; k++) {\n                eff_skill[j][k] = conf * members[j].est[k] + (1.0 - conf) * prior_cap[k];\n            }\n        }\n\n        vector<double> dynP(N, -1e100);\n        vector<pair<double,int>> order;\n        order.reserve(ready_tasks.size());\n\n        for (int task : ready_tasks) {\n            double unlock_bonus = 0.0;\n            for (int to : g[task]) {\n                if (state[to] == 0 && indeg_rem[to] == 1) {\n                    unlock_bonus += base_priority_static[to];\n                }\n            }\n            double p = base_priority_static[task] + 0.15 * unlock_bonus - 1e-4 * task;\n            dynP[task] = p;\n            order.push_back({p, task});\n        }\n\n        sort(order.begin(), order.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        auto raw_pred = [&](int member, int task) -> double {\n            return predict_duration_with_skill(eff_skill[member], task);\n        };\n\n        vector<char> used_member(M, false), used_task(N, false);\n        vector<pair<int,int>> res;\n\n        int urgent = 0;\n        if ((int)free_members.size() >= 2) {\n            urgent = min<int>((int)free_members.size(), (completed_tasks < 2 * M ? 2 : 3));\n        }\n\n        int ptr = 0;\n        while (urgent > 0 && ptr < (int)order.size()) {\n            int task = order[ptr++].second;\n            if (used_task[task]) continue;\n\n            double bestDur = 1e100;\n            int bestMember = -1;\n            for (int j : free_members) {\n                if (used_member[j]) continue;\n                double d = raw_pred(j, task);\n                if (d < bestDur - 1e-12 || (abs(d - bestDur) <= 1e-12 && j < bestMember)) {\n                    bestDur = d;\n                    bestMember = j;\n                }\n            }\n            if (bestMember == -1) break;\n\n            used_member[bestMember] = true;\n            used_task[task] = true;\n            res.push_back({bestMember, task});\n            urgent--;\n        }\n\n        vector<int> rem_members;\n        for (int j : free_members) if (!used_member[j]) rem_members.push_back(j);\n\n        vector<int> rem_tasks_order;\n        for (auto [p, t] : order) if (!used_task[t]) rem_tasks_order.push_back(t);\n\n        if (rem_members.empty() || rem_tasks_order.empty()) return res;\n\n        vector<int> cand;\n        vector<char> chosen(N, false);\n\n        if ((int)rem_tasks_order.size() <= 80) {\n            cand = rem_tasks_order;\n            for (int t : cand) chosen[t] = true;\n        } else {\n            const int TOP_PRIO = 50;\n            const int TOP_EASY = 25;\n\n            for (int i = 0; i < (int)rem_tasks_order.size() && (int)cand.size() < TOP_PRIO; i++) {\n                int t = rem_tasks_order[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            vector<int> easy = rem_tasks_order;\n            sort(easy.begin(), easy.end(), [&](int a, int b) {\n                if (global_easy_dur[a] != global_easy_dur[b]) return global_easy_dur[a] < global_easy_dur[b];\n                if (dynP[a] != dynP[b]) return dynP[a] > dynP[b];\n                return a < b;\n            });\n\n            for (int i = 0; i < (int)easy.size() && i < TOP_EASY; i++) {\n                int t = easy[i];\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n\n            int need = min<int>((int)rem_tasks_order.size(), max<int>((int)rem_members.size(), 20));\n            for (int t : rem_tasks_order) {\n                if ((int)cand.size() >= need) break;\n                if (!chosen[t]) {\n                    chosen[t] = true;\n                    cand.push_back(t);\n                }\n            }\n        }\n\n        if (cand.empty()) return res;\n\n        int n = (int)rem_members.size();\n        int m = (int)cand.size() + n; // add dummy columns\n        vector<vector<ll>> util(n, vector<ll>(m, DUMMY_UTILITY));\n\n        for (int r = 0; r < n; r++) {\n            int member = rem_members[r];\n            int oc = (int)members[member].obs.size();\n            for (int c = 0; c < (int)cand.size(); c++) {\n                int task = cand[c];\n                double dur = raw_pred(member, task);\n\n                if (oc == 0) {\n                    if (completed_tasks < M) dur *= 2.2;\n                    else if (completed_tasks < 3 * M) dur *= 1.6;\n                } else if (oc == 1 && completed_tasks < 3 * M) {\n                    dur *= 1.2;\n                }\n\n                double u = dynP[task] * 1200.0 - dur * 800.0;\n                util[r][c] = llround(u);\n            }\n        }\n\n        ll maxU = DUMMY_UTILITY;\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                maxU = max(maxU, util[i][j]);\n            }\n        }\n\n        vector<vector<ll>> cost(n, vector<ll>(m));\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < m; j++) {\n                cost[i][j] = maxU - util[i][j];\n            }\n        }\n\n        vector<int> assign = hungarian_min(cost);\n        for (int r = 0; r < n; r++) {\n            int c = assign[r];\n            if (0 <= c && c < (int)cand.size()) {\n                res.push_back({rem_members[r], cand[c]});\n            }\n        }\n\n        return res;\n    }\n\n    void run() {\n        read_input();\n        preprocess();\n\n        for (int day = 1; ; day++) {\n            auto assignments = choose_assignments(day);\n\n            // Apply assignments locally before output.\n            for (auto [j, t] : assignments) {\n                members[j].current_task = t;\n                members[j].start_day = day;\n                state[t] = 1;\n            }\n\n            cout << assignments.size();\n            for (auto [j, t] : assignments) {\n                cout << ' ' << (j + 1) << ' ' << (t + 1);\n            }\n            cout << '\\n';\n            cout.flush();\n\n            int ncomp;\n            if (!(cin >> ncomp)) return;\n            if (ncomp == -1) return;\n\n            vector<int> finished_members(ncomp);\n            for (int i = 0; i < ncomp; i++) {\n                cin >> finished_members[i];\n                --finished_members[i];\n            }\n\n            vector<int> completed_today_tasks;\n            completed_today_tasks.reserve(ncomp);\n\n            for (int j : finished_members) {\n                if (j < 0 || j >= M) continue;\n                if (!members[j].busy()) continue;\n\n                int task = members[j].current_task;\n                int dur = day - members[j].start_day + 1;\n\n                members[j].obs.push_back({task, dur});\n                members[j].current_task = -1;\n                members[j].start_day = -1;\n\n                if (0 <= task && task < N && state[task] == 1) {\n                    state[task] = 2;\n                    completed_today_tasks.push_back(task);\n                    completed_tasks++;\n                }\n\n                reestimate_member(j);\n            }\n\n            for (int task : completed_today_tasks) {\n                for (int to : g[task]) {\n                    if (state[to] == 0) {\n                        indeg_rem[to]--;\n                    }\n                }\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing u8 = unsigned char;\nusing u16 = uint16_t;\nusing u64 = uint64_t;\n\nstatic constexpr int N = 1000;\nstatic constexpr int M = 50;\nstatic constexpr int POINTS = 2 * N + 1; // 0..1999: pickups/deliveries, 2000: depot\nstatic constexpr int DEPOT = 2000;\nstatic constexpr int DEPOT_X = 400;\nstatic constexpr int DEPOT_Y = 400;\nstatic constexpr int MAX_ROUTE = 110;\nstatic constexpr int INF = 1e9;\n\nstatic u16 distMat[POINTS][POINTS];\nstatic int PX[POINTS], PY[POINTS];\n\nchrono::steady_clock::time_point g_start;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int pick_pid(int oid) { return oid << 1; }\ninline int del_pid(int oid) { return (oid << 1) | 1; }\n\nstruct Insertion {\n    int delta;\n    int gapP;\n    int gapD;\n    bool sameGap;\n};\n\nstruct Candidate {\n    int delta;\n    int oid;\n    Insertion ins;\n};\n\nstruct RouteContext {\n    int L = 0;\n    int E = 0;\n    int pid[MAX_ROUTE];\n    int edge[MAX_ROUTE];\n    int total = 0;\n};\n\nstruct Solution {\n    vector<int> route;       // point ids, includes depot at both ends\n    array<u8, N> sel{};\n    int cost = INF;\n};\n\nstatic inline u64 splitmix64(u64 x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\ninline int calc_cost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distMat[route[i]][route[i + 1]];\n    }\n    return s;\n}\n\ninline void build_context(const vector<int>& route, RouteContext& ctx) {\n    ctx.L = (int)route.size();\n    ctx.E = ctx.L - 1;\n    ctx.total = 0;\n    for (int i = 0; i < ctx.L; i++) ctx.pid[i] = route[i];\n    for (int i = 0; i < ctx.E; i++) {\n        ctx.edge[i] = distMat[ctx.pid[i]][ctx.pid[i + 1]];\n        ctx.total += ctx.edge[i];\n    }\n}\n\n// O(route length) best feasible insertion of one order.\ninline Insertion find_best_insertion(const RouteContext& ctx, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n    const u16* Dp = distMat[p];\n    const u16* Dd = distMat[d];\n    const int pd = Dp[d];\n\n    int delCost[MAX_ROUTE];\n    int suffMin[MAX_ROUTE];\n    int suffArg[MAX_ROUTE];\n\n    for (int j = 0; j < ctx.E; j++) {\n        const int u = ctx.pid[j];\n        const int v = ctx.pid[j + 1];\n        delCost[j] = (int)Dd[u] + (int)Dd[v] - ctx.edge[j];\n    }\n\n    suffMin[ctx.E] = INF;\n    suffArg[ctx.E] = -1;\n    for (int j = ctx.E - 1; j >= 0; j--) {\n        if (delCost[j] <= suffMin[j + 1]) {\n            suffMin[j] = delCost[j];\n            suffArg[j] = j;\n        } else {\n            suffMin[j] = suffMin[j + 1];\n            suffArg[j] = suffArg[j + 1];\n        }\n    }\n\n    Insertion best{INF, -1, -1, true};\n\n    for (int i = 0; i < ctx.E; i++) {\n        const int u = ctx.pid[i];\n        const int v = ctx.pid[i + 1];\n\n        int same = (int)Dp[u] + pd + (int)Dd[v] - ctx.edge[i];\n        if (same < best.delta) {\n            best = Insertion{same, i, i, true};\n        }\n\n        if (i + 1 < ctx.E) {\n            int pickCost = (int)Dp[u] + (int)Dp[v] - ctx.edge[i];\n            int later = pickCost + suffMin[i + 1];\n            if (later < best.delta) {\n                best = Insertion{later, i, suffArg[i + 1], false};\n            }\n        }\n    }\n\n    return best;\n}\n\ninline vector<int> apply_insertion(const vector<int>& route, int oid, const Insertion& ins) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n\n    vector<int> res;\n    res.reserve(route.size() + 2);\n\n    for (int i = 0; i < (int)route.size(); i++) {\n        res.push_back(route[i]);\n        if (i == ins.gapP) {\n            res.push_back(p);\n            if (ins.sameGap) res.push_back(d);\n        }\n        if (!ins.sameGap && i == ins.gapD) {\n            res.push_back(d);\n        }\n    }\n    return res;\n}\n\ninline vector<int> remove_order_from_route(const vector<int>& route, int oid) {\n    const int p = pick_pid(oid);\n    const int d = del_pid(oid);\n    vector<int> res;\n    res.reserve(route.size() - 2);\n    for (int pid : route) {\n        if (pid != p && pid != d) res.push_back(pid);\n    }\n    return res;\n}\n\ninline vector<int> filter_route_without(const vector<int>& route, const array<u8, N>& removed) {\n    vector<int> res;\n    res.reserve(route.size());\n    for (int pid : route) {\n        if (pid == DEPOT) {\n            res.push_back(pid);\n        } else {\n            int oid = pid >> 1;\n            if (!removed[oid]) res.push_back(pid);\n        }\n    }\n    return res;\n}\n\ninline vector<int> selected_ids_from_route(const vector<int>& route) {\n    vector<int> ids;\n    ids.reserve(M);\n    for (int pid : route) {\n        if (pid != DEPOT && (pid & 1) == 0) ids.push_back(pid >> 1);\n    }\n    return ids;\n}\n\ninline void compute_positions(const vector<int>& route, array<int, N>& posP, array<int, N>& posD) {\n    posP.fill(-1);\n    posD.fill(-1);\n    for (int i = 0; i < (int)route.size(); i++) {\n        int pid = route[i];\n        if (pid == DEPOT) continue;\n        int oid = pid >> 1;\n        if ((pid & 1) == 0) posP[oid] = i;\n        else posD[oid] = i;\n    }\n}\n\ninline int exact_removal_saving(const vector<int>& route, int ip, int id) {\n    if (ip > id) swap(ip, id);\n    if (id == ip + 1) {\n        int a = route[ip - 1], b = route[ip], c = route[id], d = route[id + 1];\n        return (int)distMat[a][b] + (int)distMat[b][c] + (int)distMat[c][d] - (int)distMat[a][d];\n    } else {\n        int a = route[ip - 1], b = route[ip], c = route[ip + 1];\n        int e = route[id - 1], f = route[id], g = route[id + 1];\n        return ((int)distMat[a][b] + (int)distMat[b][c] - (int)distMat[a][c]) +\n               ((int)distMat[e][f] + (int)distMat[f][g] - (int)distMat[e][g]);\n    }\n}\n\ninline void add_candidate(vector<Candidate>& bests, const Candidate& c, int K) {\n    int pos = 0;\n    while (pos < (int)bests.size() && bests[pos].delta <= c.delta) ++pos;\n    if (pos >= K) return;\n    bests.insert(bests.begin() + pos, c);\n    if ((int)bests.size() > K) bests.pop_back();\n}\n\ninline int pick_rcl_index(int sz, mt19937& rng) {\n    if (sz <= 1) return 0;\n    static const int W[12] = {32, 20, 14, 10, 8, 6, 4, 3, 2, 1, 1, 1};\n    int sum = 0;\n    for (int i = 0; i < sz; i++) sum += W[i];\n    int r = (int)(rng() % sum);\n    for (int i = 0; i < sz; i++) {\n        if (r < W[i]) return i;\n        r -= W[i];\n    }\n    return sz - 1;\n}\n\nSolution construct_solution(int seedOid, int rclK, mt19937& rng) {\n    Solution sol;\n    sol.route = {DEPOT, DEPOT};\n    sol.sel.fill(0);\n    sol.cost = 0;\n    int cnt = 0;\n\n    if (seedOid != -1) {\n        int p = pick_pid(seedOid);\n        int d = del_pid(seedOid);\n        sol.route = {DEPOT, p, d, DEPOT};\n        sol.sel[seedOid] = 1;\n        sol.cost = distMat[DEPOT][p] + distMat[p][d] + distMat[d][DEPOT];\n        cnt = 1;\n    }\n\n    for (; cnt < M; cnt++) {\n        RouteContext ctx;\n        build_context(sol.route, ctx);\n\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n    }\n\n    return sol;\n}\n\n// Remove one whole order and reinsert it optimally.\nbool best_pair_reinsert_once(Solution& sol, double deadline) {\n    vector<int> ids = selected_ids_from_route(sol.route);\n\n    int bestCost = sol.cost;\n    int bestOid = -1;\n    Insertion bestIns{};\n    vector<int> bestBase;\n\n    for (int t = 0; t < (int)ids.size(); t++) {\n        if ((t & 7) == 0 && elapsed_sec() > deadline) break;\n        int oid = ids[t];\n        vector<int> base = remove_order_from_route(sol.route, oid);\n        RouteContext ctx;\n        build_context(base, ctx);\n        Insertion ins = find_best_insertion(ctx, oid);\n        int nc = ctx.total + ins.delta;\n        if (nc < bestCost) {\n            bestCost = nc;\n            bestOid = oid;\n            bestIns = ins;\n            bestBase = move(base);\n        }\n    }\n\n    if (bestOid == -1) return false;\n    sol.route = apply_insertion(bestBase, bestOid, bestIns);\n    sol.cost = bestCost;\n    return true;\n}\n\n// Cheap route polishing: swap adjacent nodes if precedence remains valid.\nbool best_adjacent_swap_once(Solution& sol, double deadline) {\n    const vector<int>& route = sol.route;\n    int L = (int)route.size();\n    if (L <= 3) return false;\n\n    array<int, N> posP, posD;\n    compute_positions(route, posP, posD);\n\n    int bestDelta = 0;\n    int bestI = -1;\n\n    for (int i = 1; i + 2 < L; i++) {\n        if ((i & 15) == 0 && elapsed_sec() > deadline) break;\n\n        int x = route[i];\n        int y = route[i + 1];\n        int ox = x >> 1;\n        int oy = y >> 1;\n\n        int pox = posP[ox], dox = posD[ox];\n        int poy = posP[oy], doy = posD[oy];\n\n        if ((x & 1) == 0) pox = i + 1;\n        else dox = i + 1;\n\n        if ((y & 1) == 0) poy = i;\n        else doy = i;\n\n        bool ok;\n        if (ox == oy) ok = (pox < dox);\n        else ok = (pox < dox) && (poy < doy);\n        if (!ok) continue;\n\n        int a = route[i - 1];\n        int b = route[i + 2];\n        int oldCost = (int)distMat[a][x] + (int)distMat[x][y] + (int)distMat[y][b];\n        int newCost = (int)distMat[a][y] + (int)distMat[y][x] + (int)distMat[x][b];\n        int delta = newCost - oldCost;\n\n        if (delta < bestDelta) {\n            bestDelta = delta;\n            bestI = i;\n        }\n    }\n\n    if (bestI == -1) return false;\n    swap(sol.route[bestI], sol.route[bestI + 1]);\n    sol.cost += bestDelta;\n    return true;\n}\n\n// More expensive move: relocate one pickup or one delivery while preserving precedence.\nbool best_node_relocate_once(Solution& sol, double deadline) {\n    const vector<int>& route = sol.route;\n    int L = (int)route.size();\n\n    array<int, N> posP, posD;\n    compute_positions(route, posP, posD);\n\n    int bestDelta = 0;\n    int bestI = -1;\n    int bestGap = -1;\n\n    for (int i = 1; i + 1 < L; i++) {\n        if ((i & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int pid = route[i];\n        int oid = pid >> 1;\n        bool isPickup = ((pid & 1) == 0);\n\n        vector<int> rem;\n        rem.reserve(L - 1);\n        for (int k = 0; k < L; k++) {\n            if (k != i) rem.push_back(route[k]);\n        }\n\n        int len = (int)rem.size();\n        int otherPos = isPickup ? posD[oid] : posP[oid];\n        int otherPosRem = otherPos - (otherPos > i ? 1 : 0);\n\n        int lo = 0, hi = len - 2;\n        if (isPickup) {\n            hi = otherPosRem - 1;\n        } else {\n            lo = otherPosRem;\n        }\n        if (lo > hi) continue;\n\n        int remSaving =\n            (int)distMat[route[i - 1]][pid] +\n            (int)distMat[pid][route[i + 1]] -\n            (int)distMat[route[i - 1]][route[i + 1]];\n\n        for (int g = lo; g <= hi; g++) {\n            int u = rem[g];\n            int v = rem[g + 1];\n            int insCost =\n                (int)distMat[u][pid] +\n                (int)distMat[pid][v] -\n                (int)distMat[u][v];\n            int delta = -remSaving + insCost;\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestI = i;\n                bestGap = g;\n            }\n        }\n    }\n\n    if (bestI == -1) return false;\n\n    int pid = sol.route[bestI];\n    vector<int> rem;\n    rem.reserve(sol.route.size() - 1);\n    for (int k = 0; k < (int)sol.route.size(); k++) {\n        if (k != bestI) rem.push_back(sol.route[k]);\n    }\n\n    vector<int> res;\n    res.reserve(sol.route.size());\n    for (int k = 0; k < (int)rem.size(); k++) {\n        res.push_back(rem[k]);\n        if (k == bestGap) res.push_back(pid);\n    }\n\n    sol.route.swap(res);\n    sol.cost += bestDelta;\n    return true;\n}\n\n// Replace one selected order with one unselected order.\nbool best_single_replace_once(Solution& sol, double deadline) {\n    vector<int> selIds = selected_ids_from_route(sol.route);\n\n    int bestCost = sol.cost;\n    int remOid = -1, addOid = -1;\n    Insertion bestIns{};\n    vector<int> bestBase;\n\n    for (int si = 0; si < (int)selIds.size(); si++) {\n        if ((si & 3) == 0 && elapsed_sec() > deadline) break;\n\n        int x = selIds[si];\n        vector<int> base = remove_order_from_route(sol.route, x);\n        RouteContext ctx;\n        build_context(base, ctx);\n\n        int localBestCost = INF;\n        int bestY = -1;\n        Insertion localIns{};\n\n        for (int y = 0; y < N; y++) {\n            if (sol.sel[y]) continue;\n            Insertion ins = find_best_insertion(ctx, y);\n            int c = ctx.total + ins.delta;\n            if (c < localBestCost) {\n                localBestCost = c;\n                bestY = y;\n                localIns = ins;\n            }\n        }\n\n        if (localBestCost < bestCost) {\n            bestCost = localBestCost;\n            remOid = x;\n            addOid = bestY;\n            bestIns = localIns;\n            bestBase = move(base);\n        }\n    }\n\n    if (remOid == -1) return false;\n\n    sol.sel[remOid] = 0;\n    sol.sel[addOid] = 1;\n    sol.route = apply_insertion(bestBase, addOid, bestIns);\n    sol.cost = bestCost;\n    return true;\n}\n\nvector<int> choose_removals(const Solution& sol, int mode, int K, mt19937& rng) {\n    K = min(K, M);\n    vector<int> selIds = selected_ids_from_route(sol.route);\n\n    vector<int> res;\n    res.reserve(K);\n    array<u8, N> used{};\n    used.fill(0);\n\n    auto add_oid = [&](int oid) {\n        if (!used[oid]) {\n            used[oid] = 1;\n            res.push_back(oid);\n        }\n    };\n\n    if (mode == 0) {\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int i = 0; i < K; i++) add_oid(selIds[i]);\n    } else if (mode == 1) {\n        array<int, N> posP, posD;\n        compute_positions(sol.route, posP, posD);\n        vector<pair<int, int>> sav;\n        sav.reserve(M);\n        for (int oid : selIds) {\n            int s = exact_removal_saving(sol.route, posP[oid], posD[oid]);\n            sav.push_back({s, oid});\n        }\n        sort(sav.rbegin(), sav.rend());\n        for (int i = 0; i < K; i++) add_oid(sav[i].second);\n    } else if (mode == 2) {\n        int L = (int)sol.route.size();\n        int st = 1 + (int)(rng() % (L - 2));\n        int span = min(L - 2, st + 2 * K + 6);\n        for (int i = st; i <= span && (int)res.size() < K; i++) {\n            int pid = sol.route[i];\n            if (pid != DEPOT) add_oid(pid >> 1);\n        }\n        if ((int)res.size() < K) {\n            shuffle(selIds.begin(), selIds.end(), rng);\n            for (int oid : selIds) {\n                if ((int)res.size() >= K) break;\n                add_oid(oid);\n            }\n        }\n    } else if (mode == 3) {\n        int base = selIds[(int)(rng() % selIds.size())];\n        int bp = pick_pid(base), bd = del_pid(base);\n        vector<pair<int, int>> sim;\n        sim.reserve(M);\n        for (int oid : selIds) {\n            int s = (int)distMat[bp][pick_pid(oid)] + (int)distMat[bd][del_pid(oid)];\n            s += (int)(rng() % 50);\n            sim.push_back({s, oid});\n        }\n        sort(sim.begin(), sim.end());\n        for (int i = 0; i < K; i++) add_oid(sim[i].second);\n    } else {\n        array<int, N> posP, posD;\n        compute_positions(sol.route, posP, posD);\n        vector<pair<int, int>> sav;\n        sav.reserve(M);\n        for (int oid : selIds) {\n            int s = exact_removal_saving(sol.route, posP[oid], posD[oid]);\n            sav.push_back({s, oid});\n        }\n        sort(sav.rbegin(), sav.rend());\n        int takeW = max(1, K / 2);\n        for (int i = 0; i < takeW; i++) add_oid(sav[i].second);\n\n        int base = selIds[(int)(rng() % selIds.size())];\n        int bp = pick_pid(base), bd = del_pid(base);\n        vector<pair<int, int>> sim;\n        sim.reserve(M);\n        for (int oid : selIds) {\n            int s = (int)distMat[bp][pick_pid(oid)] + (int)distMat[bd][del_pid(oid)];\n            s += (int)(rng() % 50);\n            sim.push_back({s, oid});\n        }\n        sort(sim.begin(), sim.end());\n        for (auto& [_, oid] : sim) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n        shuffle(selIds.begin(), selIds.end(), rng);\n        for (int oid : selIds) {\n            if ((int)res.size() >= K) break;\n            add_oid(oid);\n        }\n    }\n\n    return res;\n}\n\nSolution destroy_repair(const Solution& base, int mode, int K, int rclK, bool forbidRemoved, mt19937& rng) {\n    vector<int> rem = choose_removals(base, mode, K, rng);\n\n    Solution sol;\n    sol.sel = base.sel;\n\n    array<u8, N> removed{};\n    removed.fill(0);\n    array<u8, N> banned{};\n    banned.fill(0);\n\n    for (int oid : rem) {\n        removed[oid] = 1;\n        if (forbidRemoved) banned[oid] = 1;\n        sol.sel[oid] = 0;\n    }\n\n    sol.route = filter_route_without(base.route, removed);\n    RouteContext ctx;\n    build_context(sol.route, ctx);\n    sol.cost = ctx.total;\n\n    int cnt = M - (int)rem.size();\n    while (cnt < M) {\n        build_context(sol.route, ctx);\n\n        vector<Candidate> bests;\n        bests.reserve(rclK);\n\n        for (int oid = 0; oid < N; oid++) {\n            if (sol.sel[oid]) continue;\n            if (banned[oid]) continue;\n            Insertion ins = find_best_insertion(ctx, oid);\n            add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n        }\n\n        if (bests.empty()) {\n            for (int oid = 0; oid < N; oid++) banned[oid] = 0;\n            for (int oid = 0; oid < N; oid++) {\n                if (sol.sel[oid]) continue;\n                Insertion ins = find_best_insertion(ctx, oid);\n                add_candidate(bests, Candidate{ins.delta, oid, ins}, rclK);\n            }\n        }\n\n        int idx = pick_rcl_index((int)bests.size(), rng);\n        const Candidate& c = bests[idx];\n        sol.route = apply_insertion(sol.route, c.oid, c.ins);\n        sol.sel[c.oid] = 1;\n        sol.cost = ctx.total + c.delta;\n        cnt++;\n    }\n\n    return sol;\n}\n\ninline double rand01(mt19937& rng) {\n    return double(rng()) * (1.0 / 4294967296.0);\n}\n\n// Main-loop optimizer: cheap and robust.\nvoid local_opt_search(Solution& sol, double deadline, int maxReplace) {\n    int rep = 0;\n    while (elapsed_sec() < deadline) {\n        if (best_pair_reinsert_once(sol, deadline)) continue;\n        if (best_adjacent_swap_once(sol, deadline)) continue;\n        if (rep < maxReplace && best_single_replace_once(sol, deadline)) {\n            rep++;\n            continue;\n        }\n        break;\n    }\n}\n\n// Final intensification: includes expensive single-node relocate.\nvoid local_opt_final(Solution& sol, double deadline, int maxReplace) {\n    int rep = 0;\n    while (elapsed_sec() < deadline) {\n        if (best_pair_reinsert_once(sol, deadline)) continue;\n        if (best_adjacent_swap_once(sol, deadline)) continue;\n        if (best_node_relocate_once(sol, deadline)) continue;\n        if (rep < maxReplace && best_single_replace_once(sol, deadline)) {\n            rep++;\n            continue;\n        }\n        break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    u64 h = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n        PX[pick_pid(i)] = a;\n        PY[pick_pid(i)] = b;\n        PX[del_pid(i)] = c;\n        PY[del_pid(i)] = d;\n        h = splitmix64(h ^ (u64)(a + 1009 * b + 9176 * c + 65537 * d + i * 1315423911u));\n    }\n    PX[DEPOT] = DEPOT_X;\n    PY[DEPOT] = DEPOT_Y;\n\n    g_start = chrono::steady_clock::now();\n\n    for (int i = 0; i < POINTS; i++) {\n        for (int j = 0; j < POINTS; j++) {\n            distMat[i][j] = (u16)(abs(PX[i] - PX[j]) + abs(PY[i] - PY[j]));\n        }\n    }\n\n    mt19937 rng((uint32_t)(h ^ (h >> 32)));\n\n    vector<pair<int, int>> centerRank;\n    centerRank.reserve(N);\n    for (int oid = 0; oid < N; oid++) {\n        int p = pick_pid(oid), d = del_pid(oid);\n        int sc = (int)distMat[DEPOT][p] + (int)distMat[p][d] + (int)distMat[d][DEPOT];\n        centerRank.push_back({sc, oid});\n    }\n    sort(centerRank.begin(), centerRank.end());\n\n    vector<int> seedPool;\n    for (int i = 0; i < min(250, N); i++) seedPool.push_back(centerRank[i].second);\n\n    const double INIT_DEADLINE = 0.50;\n    const double SEARCH_DEADLINE = 1.86;\n    const double FINAL_DEADLINE = 1.97;\n\n    Solution best;\n    bool hasBest = false;\n\n    auto update_best = [&](Solution&& sol) {\n        if (!hasBest || sol.cost < best.cost) {\n            best = move(sol);\n            hasBest = true;\n        }\n    };\n\n    // Deterministic / semi-deterministic initial constructions.\n    {\n        Solution sol = construct_solution(-1, 1, rng);\n        local_opt_search(sol, INIT_DEADLINE, 1);\n        update_best(move(sol));\n    }\n\n    for (int i = 0; i < 4 && elapsed_sec() < INIT_DEADLINE; i++) {\n        Solution sol = construct_solution(seedPool[i], 1, rng);\n        local_opt_search(sol, INIT_DEADLINE, 1);\n        update_best(move(sol));\n    }\n\n    // Randomized multistarts.\n    while (elapsed_sec() < INIT_DEADLINE) {\n        int seed = ((rng() & 3) == 0 ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 120))]);\n        int rcl = 5 + (int)(rng() % 6); // 5..10\n        Solution sol = construct_solution(seed, rcl, rng);\n        if ((rng() & 1) == 0) {\n            if ((rng() & 1) == 0) best_pair_reinsert_once(sol, INIT_DEADLINE);\n            else best_adjacent_swap_once(sol, INIT_DEADLINE);\n        }\n        update_best(move(sol));\n    }\n\n    Solution current = best;\n    int iter = 0;\n    int stagn = 0;\n\n    while (elapsed_sec() < SEARCH_DEADLINE) {\n        if ((iter % 12) == 0) {\n            local_opt_search(current, SEARCH_DEADLINE, 0);\n            if (current.cost < best.cost) best = current;\n        }\n\n        double progress = max(0.0, min(1.0, (elapsed_sec() - INIT_DEADLINE) / (SEARCH_DEADLINE - INIT_DEADLINE)));\n        double temp = 55.0 * pow(2.0 / 55.0, progress);\n\n        int mode = (int)(rng() % 5);\n        int K = 3 + (int)(rng() % 6); // 3..8\n        if (stagn >= 10) K += 2;\n        if (stagn >= 20) K += 2;\n        if (K > 12) K = 12;\n\n        int rcl = 4 + (int)(rng() % 6); // 4..9\n        bool forbidRemoved = ((rng() % 100) < 80);\n\n        Solution cand = destroy_repair(current, mode, K, rcl, forbidRemoved, rng);\n\n        // Quick polishing: cheap moves first.\n        int coin = (int)(rng() % 100);\n        if (coin < 55) best_pair_reinsert_once(cand, SEARCH_DEADLINE);\n        else if (coin < 90) best_adjacent_swap_once(cand, SEARCH_DEADLINE);\n\n        if ((rng() % 100) < 15) best_node_relocate_once(cand, SEARCH_DEADLINE);\n        if ((rng() % 100) < 8) best_single_replace_once(cand, SEARCH_DEADLINE);\n\n        if (cand.cost < best.cost) {\n            best = cand;\n            local_opt_search(best, SEARCH_DEADLINE, 1);\n            if (best.cost < cand.cost) cand = best;\n            stagn = 0;\n        } else {\n            stagn++;\n        }\n\n        int diff = cand.cost - current.cost;\n        bool accept = false;\n        if (diff <= 0) {\n            accept = true;\n        } else {\n            double prob = exp(-double(diff) / temp);\n            if (rand01(rng) < prob) accept = true;\n        }\n\n        if (accept) current = move(cand);\n\n        if (stagn >= 30 && elapsed_sec() < 1.68) {\n            if (rng() & 1) {\n                current = best;\n            } else {\n                int seed = ((rng() & 1) ? -1 : seedPool[(int)(rng() % min<int>((int)seedPool.size(), 150))]);\n                current = construct_solution(seed, 8, rng);\n                if ((rng() & 1) == 0) best_pair_reinsert_once(current, SEARCH_DEADLINE);\n                else best_adjacent_swap_once(current, SEARCH_DEADLINE);\n            }\n            stagn = 0;\n        }\n\n        iter++;\n    }\n\n    local_opt_search(best, FINAL_DEADLINE, 3);\n    local_opt_final(best, FINAL_DEADLINE, 8);\n    best.cost = calc_cost(best.route);\n\n    vector<int> ids = selected_ids_from_route(best.route);\n\n    cout << ids.size();\n    for (int oid : ids) cout << ' ' << (oid + 1);\n    cout << '\\n';\n\n    cout << best.route.size();\n    for (int pid : best.route) {\n        cout << ' ' << PX[pid] << ' ' << PY[pid];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p;\n    DSU() {}\n    DSU(int n) : p(n, -1) {}\n\n    int leader(int x) {\n        if (p[x] < 0) return x;\n        return p[x] = leader(p[x]);\n    }\n    bool same(int a, int b) {\n        return leader(a) == leader(b);\n    }\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(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        return true;\n    }\n};\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nstatic double clamp01(double x) {\n    if (x < 0.0) return 0.0;\n    if (x > 1.0) return 1.0;\n    return x;\n}\n\n// Approximate E[max(path edge lengths)] / mx for path edges with true lengths U[d, 3d].\nstatic double expected_bottleneck_factor(const vector<int>& pathd, int mx) {\n    if (pathd.empty() || mx <= 0) return 2.0;\n\n    vector<int> rel;\n    rel.reserve(pathd.size());\n    for (int d : pathd) {\n        if (3 * d > mx) rel.push_back(d);\n    }\n\n    constexpr int SEG = 16; // even\n    const double h = 2.0 / SEG;\n\n    auto tail_prob = [&](double x) -> double {\n        double t = mx * x;\n        double prod = 1.0;\n        for (int d : rel) {\n            if (t <= d) return 1.0;\n            if (t >= 3.0 * d) continue;\n            prod *= (t - d) / (2.0 * d);\n            if (prod < 1e-15) return 1.0;\n        }\n        double ret = 1.0 - prod;\n        if (ret < 0.0) ret = 0.0;\n        if (ret > 1.0) ret = 1.0;\n        return ret;\n    };\n\n    double sum = 0.0;\n    for (int s = 0; s <= SEG; s++) {\n        double x = 1.0 + h * s;\n        int coef = (s == 0 || s == SEG ? 1 : (s & 1 ? 4 : 2));\n        sum += coef * tail_prob(x);\n    }\n    double integral = h * sum / 3.0;\n    double ans = 1.0 + integral;\n\n    if (ans < 2.0) ans = 2.0;\n    if (ans > 3.0) ans = 3.0;\n    return ans;\n}\n\n// P(max(path edge lengths) >= L) for independent path edge lengths U[d, 3d].\nstatic double tail_prob_ge_L(const vector<int>& pathd, int L) {\n    if (pathd.empty()) return 0.0;\n    long double prod = 1.0L;\n\n    for (int d : pathd) {\n        if (L <= d) return 1.0;\n        if (L >= 3 * d) continue;\n        prod *= (long double)(L - d) / (long double)(2 * d);\n        if (prod < 1e-18L) return 1.0;\n    }\n\n    long double ret = 1.0L - prod;\n    if (ret < 0.0L) ret = 0.0L;\n    if (ret > 1.0L) ret = 1.0L;\n    return (double)ret;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    vector<int> xs(N), ys(N);\n    for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n    vector<int> U(M), V(M), D(M);\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n        long long dx = xs[U[i]] - xs[V[i]];\n        long long dy = ys[U[i]] - ys[V[i]];\n        D[i] = (int)llround(sqrt((double)(dx * dx + dy * dy)));\n    }\n\n    vector<int> ord(M);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    // Reconstruct approximate generator layers by repeatedly peeling d-MSTs.\n    vector<int> layer(M, 4);\n    vector<char> alive(M, 1);\n    for (int rep = 0; rep < 5; rep++) {\n        DSU uf(N);\n        int cnt = 0;\n        for (int e : ord) {\n            if (!alive[e]) continue;\n            if (uf.merge(U[e], V[e])) {\n                layer[e] = rep;\n                alive[e] = 0;\n                cnt++;\n                if (cnt == N - 1) break;\n            }\n        }\n    }\n\n    const double layer_bonus_base[5] = {\n        +0.045, +0.020, 0.000, -0.018, -0.035\n    };\n\n    DSU adopted(N);\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        if (!(cin >> l)) return 0;\n\n        int u = U[i], v = V[i];\n\n        if (adopted.same(u, v)) {\n            cout << 0 << '\\n' << flush;\n            continue;\n        }\n\n        // Compress adopted components.\n        vector<int> root_id(N, -1), cid(N, -1);\n        int C = 0;\n        for (int x = 0; x < N; x++) {\n            int r = adopted.leader(x);\n            if (root_id[r] == -1) root_id[r] = C++;\n            cid[x] = root_id[r];\n        }\n\n        int cu = cid[u], cv = cid[v];\n\n        // Build future-only MST on current components using d as surrogate.\n        DSU uf2(C);\n        vector<vector<pair<int,int>>> tree(C); // (to, edge_id)\n        int used = 0;\n        int useful_edges = 0;\n\n        for (int e : ord) {\n            if (e <= i) continue;\n            int a = cid[U[e]];\n            int b = cid[V[e]];\n            if (a == b) continue;\n\n            useful_edges++;\n            if (uf2.merge(a, b)) {\n                tree[a].push_back({b, e});\n                tree[b].push_back({a, e});\n                used++;\n            }\n        }\n\n        // Mandatory edge if future-only graph is disconnected.\n        if (used < C - 1) {\n            cout << 1 << '\\n' << flush;\n            adopted.merge(u, v);\n            continue;\n        }\n\n        // Recover path in future MST.\n        vector<int> parent(C, -1), pedge(C, -1);\n        queue<int> q;\n        parent[cu] = cu;\n        q.push(cu);\n\n        while (!q.empty() && parent[cv] == -1) {\n            int x = q.front();\n            q.pop();\n            for (auto [to, eid] : tree[x]) {\n                if (parent[to] != -1) continue;\n                parent[to] = x;\n                pedge[to] = eid;\n                q.push(to);\n            }\n        }\n\n        if (parent[cv] == -1) {\n            cout << 1 << '\\n' << flush;\n            adopted.merge(u, v);\n            continue;\n        }\n\n        vector<int> pathd;\n        vector<int> pathe;\n        int mx = 0;\n        for (int cur = cv; cur != cu; cur = parent[cur]) {\n            int eid = pedge[cur];\n            pathe.push_back(eid);\n            pathd.push_back(D[eid]);\n            mx = max(mx, D[eid]);\n        }\n\n        double density = (C <= 1 ? 10.0 : (double)useful_edges / (double)(C - 1));\n        double t = clamp01((density - 1.0) / 4.0); // 0 sparse, 1 dense\n        double sparse = 1.0 - t;\n        double progress = (double)i / (double)(M - 1);\n\n        // Main robust threshold.\n        double lambda = 2.05 - 0.45 * t;\n\n        // Path-randomness correction.\n        double beta = expected_bottleneck_factor(pathd, mx); // in [2,3]\n        lambda += 0.25 * (beta - 2.0);\n\n        // Late-stage safety bump.\n        lambda += 0.04 * progress * sparse;\n\n        // Positive-only geometric bonus, stronger when future is sparse.\n        if (D[i] < mx) {\n            double bonus = 0.095 * (1.0 - (double)D[i] / (double)mx);\n            bonus *= (0.85 + 0.30 * sparse + 0.10 * progress);\n            if (bonus > 0.065) bonus = 0.065;\n            lambda += bonus;\n        }\n\n        // Asymmetric structural prior from reconstructed layer.\n        {\n            double lb = layer_bonus_base[layer[i]];\n            if (lb >= 0.0) {\n                lambda += lb * (0.80 + 0.35 * sparse);\n            } else {\n                lambda += lb * (0.55 + 0.20 * sparse);\n            }\n        }\n\n        // Path-structure refinement.\n        if (!pathe.empty()) {\n            double avg_layer = 0.0;\n            int max_layer = 0;\n            for (int eid : pathe) {\n                avg_layer += layer[eid];\n                max_layer = max(max_layer, layer[eid]);\n            }\n            avg_layer /= (double)pathe.size();\n\n            double diff_avg = avg_layer - (double)layer[i];\n            if (diff_avg > 0.0) {\n                double bonus = 0.0105 * diff_avg * (0.75 + 0.50 * sparse);\n                if (bonus > 0.028) bonus = 0.028;\n                lambda += bonus;\n            }\n\n            int diff_max = max_layer - layer[i];\n            if (diff_max > 0) {\n                double bonus = 0.0035 * diff_max * (0.60 + 0.60 * sparse);\n                if (bonus > 0.014) bonus = 0.014;\n                lambda += bonus;\n            }\n        }\n\n        // l-specific correction from the surrogate replacement path.\n        {\n            double ptail = tail_prob_ge_L(pathd, l); // in [0,1]\n            double adj = (0.015 + 0.040 * sparse) * (ptail - 0.50);\n            if (adj < -0.012) adj = -0.012;\n            if (adj > +0.032) adj = +0.032;\n            lambda += adj;\n        }\n\n        // Local redundancy bonuses around the endpoint components.\n        {\n            vector<char> seen_u(C, 0), seen_v(C, 0);\n            vector<char> seen_u_lt(C, 0), seen_v_lt(C, 0);\n            int deg_u = 0, deg_v = 0;\n            int deg_u_lt = 0, deg_v_lt = 0;\n\n            for (int e = i + 1; e < M; e++) {\n                int d = D[e];\n                if (d > mx) continue;\n\n                int a = cid[U[e]];\n                int b = cid[V[e]];\n                if (a == b) continue;\n\n                if (a == cu && b != cu && !seen_u[b]) {\n                    seen_u[b] = 1;\n                    deg_u++;\n                } else if (b == cu && a != cu && !seen_u[a]) {\n                    seen_u[a] = 1;\n                    deg_u++;\n                }\n\n                if (a == cv && b != cv && !seen_v[b]) {\n                    seen_v[b] = 1;\n                    deg_v++;\n                } else if (b == cv && a != cv && !seen_v[a]) {\n                    seen_v[a] = 1;\n                    deg_v++;\n                }\n\n                if (d < mx) {\n                    if (a == cu && b != cu && !seen_u_lt[b]) {\n                        seen_u_lt[b] = 1;\n                        deg_u_lt++;\n                    } else if (b == cu && a != cu && !seen_u_lt[a]) {\n                        seen_u_lt[a] = 1;\n                        deg_u_lt++;\n                    }\n\n                    if (a == cv && b != cv && !seen_v_lt[b]) {\n                        seen_v_lt[b] = 1;\n                        deg_v_lt++;\n                    } else if (b == cv && a != cv && !seen_v_lt[a]) {\n                        seen_v_lt[a] = 1;\n                        deg_v_lt++;\n                    }\n                }\n            }\n\n            // Existing low-bottleneck branching bonus (d <= mx).\n            int mindeg = min(deg_u, deg_v);\n            double bonus = 0.0;\n            if (mindeg <= 1) bonus = 0.022;\n            else if (mindeg == 2) bonus = 0.011;\n            else if (mindeg == 3) bonus = 0.0045;\n            if ((int)pathd.size() <= 1) bonus *= 0.85;\n            bonus *= (0.55 + 0.70 * sparse);\n            lambda += bonus;\n\n            // New micro-bonus: strict-below-bottleneck branching (d < mx).\n            // If one endpoint has almost no strictly better alternatives, the path is fragile.\n            int mindeg_lt = min(deg_u_lt, deg_v_lt);\n            double bonus_lt = 0.0;\n            if (mindeg_lt == 0) bonus_lt = 0.012;\n            else if (mindeg_lt == 1) bonus_lt = 0.005;\n\n            if ((int)pathd.size() <= 1) bonus_lt *= 0.70;\n            bonus_lt *= (0.50 + 0.75 * sparse);\n            lambda += bonus_lt;\n        }\n\n        if (lambda < 1.50) lambda = 1.50;\n        if (lambda > 2.30) lambda = 2.30;\n\n        int ans = ((double)l <= lambda * (double)mx + 1e-9) ? 1 : 0;\n\n        cout << ans << '\\n' << flush;\n        if (ans) adopted.merge(u, v);\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int S = 30;\nstatic constexpr int MAX_TURN = 300;\nstatic constexpr int INF = 1e9;\n\nint dr[4] = {-1, 1, 0, 0};\nint dc[4] = {0, 0, -1, 1};\nchar moveChar[4] = {'U', 'D', 'L', 'R'};\n\nstruct Task {\n    int wr, wc;\n    int sr, sc;\n    char act;\n};\n\nstruct Door {\n    int wr, wc;\n    int sr, sc;\n    char act;\n};\n\nstruct Room {\n    int r1, r2, c1, c2;\n    int br, bc;\n    int centerR, centerC;\n    array<Door, 2> doors;\n    vector<Task> tasks;\n\n    bool inside(int r, int c) const {\n        return r1 <= r && r <= r2 && c1 <= c && c <= c2;\n    }\n    int area() const {\n        return (r2 - r1 + 1) * (c2 - c1 + 1);\n    }\n};\n\nstruct BFSRes {\n    int dist[S][S];\n    char first[S][S];\n    BFSRes() {\n        for (int i = 0; i < S; i++) {\n            for (int j = 0; j < S; j++) {\n                dist[i][j] = -1;\n                first[i][j] = 0;\n            }\n        }\n    }\n};\n\nstruct RoomEval {\n    double aggressiveScore = -1e100;\n    double safeScore = -1e100;\n    int insidePets = 0;\n    int insideDogs = 0;\n    int expandedPets = 0;\n    int nearDoorPets = 0;\n    int nearDoorDogs = 0;\n    int sumBest = 0;\n    int tasks = 0;\n};\n\nint N, M;\nvector<pair<int,int>> petsPos;\nvector<int> petsType;\nvector<pair<int,int>> humansPos;\narray<array<bool, S>, S> wallCell;\n\ninline bool inb(int r, int c) {\n    return 0 <= r && r < S && 0 <= c && c < S;\n}\n\nbool is_lower_act(char c) {\n    return c == 'u' || c == 'd' || c == 'l' || c == 'r';\n}\nbool is_upper_act(char c) {\n    return c == 'U' || c == 'D' || c == 'L' || c == 'R';\n}\n\npair<int,int> apply_dir(pair<int,int> p, char ch) {\n    if (ch == 'U' || ch == 'u') return {p.first - 1, p.second};\n    if (ch == 'D' || ch == 'd') return {p.first + 1, p.second};\n    if (ch == 'L' || ch == 'l') return {p.first, p.second - 1};\n    if (ch == 'R' || ch == 'r') return {p.first, p.second + 1};\n    return p;\n}\n\nint count_dogs() {\n    int x = 0;\n    for (int t : petsType) if (t == 4) x++;\n    return x;\n}\n\nRoom make_room(int corner, int H, int W) {\n    // 0 TL, 1 TR, 2 BL, 3 BR\n    bool top = (corner == 0 || corner == 1);\n    bool left = (corner == 0 || corner == 2);\n\n    Room room;\n    if (top) {\n        room.r1 = 0;\n        room.r2 = H - 1;\n        room.br = H;\n    } else {\n        room.r1 = S - H;\n        room.r2 = S - 1;\n        room.br = S - H - 1;\n    }\n\n    if (left) {\n        room.c1 = 0;\n        room.c2 = W - 1;\n        room.bc = W;\n    } else {\n        room.c1 = S - W;\n        room.c2 = S - 1;\n        room.bc = S - W - 1;\n    }\n\n    room.centerR = (room.r1 + room.r2) / 2;\n    room.centerC = (room.c1 + room.c2) / 2;\n\n    int insideRow = top ? room.r2 : room.r1;\n    char hAct = top ? 'd' : 'u';\n\n    int d1 = room.c1 + (W - 1) / 3;\n    int d2 = room.c1 + (2 * (W - 1)) / 3;\n    if (d1 == d2) {\n        if (d2 < room.c2) d2++;\n        else if (d1 > room.c1) d1--;\n    }\n    if (d1 > d2) swap(d1, d2);\n\n    room.doors[0] = Door{room.br, d1, insideRow, d1, hAct};\n    room.doors[1] = Door{room.br, d2, insideRow, d2, hAct};\n\n    room.tasks.clear();\n\n    for (int c = room.c1; c <= room.c2; c++) {\n        if (c == d1 || c == d2) continue;\n        room.tasks.push_back(Task{room.br, c, insideRow, c, hAct});\n    }\n\n    int insideCol = left ? room.c2 : room.c1;\n    char vAct = left ? 'r' : 'l';\n    for (int r = room.r1; r <= room.r2; r++) {\n        room.tasks.push_back(Task{r, room.bc, r, insideCol, vAct});\n    }\n\n    return room;\n}\n\nint dist_to_rect(const Room& room, int r, int c) {\n    int vr = 0, vc = 0;\n    if (r < room.r1) vr = room.r1 - r;\n    else if (r > room.r2) vr = r - room.r2;\n    if (c < room.c1) vc = room.c1 - c;\n    else if (c > room.c2) vc = c - room.c2;\n    return vr + vc;\n}\n\nint nearest_door_dist(const Room& room, int r, int c) {\n    int d0 = abs(r - room.doors[0].wr) + abs(c - room.doors[0].wc);\n    int d1 = abs(r - room.doors[1].wr) + abs(c - room.doors[1].wc);\n    return min(d0, d1);\n}\n\nRoomEval evaluate_room(const Room& room) {\n    RoomEval e;\n    int dogCnt = count_dogs();\n    int reqBase = max(1, M - (dogCnt > 0 ? 1 : 0));\n\n    e.tasks = (int)room.tasks.size();\n\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        if (room.inside(r, c)) {\n            e.insidePets++;\n            if (petsType[i] == 4) e.insideDogs++;\n        }\n        if (room.r1 - 1 <= r && r <= room.r2 + 1 &&\n            room.c1 - 1 <= c && c <= room.c2 + 1) {\n            e.expandedPets++;\n        }\n        int dd = nearest_door_dist(room, r, c);\n        if (dd <= 3) e.nearDoorPets += (4 - dd);\n        if (petsType[i] == 4 && dd <= 6) e.nearDoorDogs += (7 - dd);\n    }\n\n    vector<int> hdist;\n    hdist.reserve(M);\n    for (int i = 0; i < M; i++) {\n        auto [r, c] = humansPos[i];\n        hdist.push_back(dist_to_rect(room, r, c));\n    }\n    sort(hdist.begin(), hdist.end());\n    for (int i = 0; i < min(reqBase, (int)hdist.size()); i++) e.sumBest += hdist[i];\n\n    {\n        double score = 0.0;\n        score += 5000.0 * room.area();\n        score -= 35.0 * e.sumBest;\n        score -= 100.0 * e.tasks;\n        score -= 250.0 * e.expandedPets;\n        score -= 700.0 * e.nearDoorPets;\n        score -= 1400.0 * e.nearDoorDogs;\n        if (e.insidePets == 0) score += 5e6;\n        score -= 2.3e6 * e.insidePets;\n        score -= 1.5e6 * e.insideDogs;\n        e.aggressiveScore = score;\n    }\n\n    {\n        double score = 0.0;\n        score += 2600.0 * room.area();\n        score -= 60.0 * e.sumBest;\n        score -= 185.0 * e.tasks;\n        score -= 650.0 * e.expandedPets;\n        score -= 1250.0 * e.nearDoorPets;\n        score -= 2900.0 * e.nearDoorDogs;\n        if (e.insidePets == 0) score += 6.2e6;\n        score -= 3.4e6 * e.insidePets;\n        score -= 2.6e6 * e.insideDogs;\n        e.safeScore = score;\n    }\n\n    return e;\n}\n\nRoom choose_room() {\n    Room bestAgg = make_room(0, 8, 8);\n    Room bestSafe = make_room(0, 6, 6);\n    RoomEval bestAggEval, bestSafeEval;\n    double bestAggScore = -1e100;\n    double bestSafeScore = -1e100;\n\n    for (int H = 5; H <= 14; H++) {\n        for (int W = 5; W <= 14; W++) {\n            for (int corner = 0; corner < 4; corner++) {\n                Room room = make_room(corner, H, W);\n                RoomEval e = evaluate_room(room);\n                if (e.aggressiveScore > bestAggScore) {\n                    bestAggScore = e.aggressiveScore;\n                    bestAgg = room;\n                    bestAggEval = e;\n                }\n            }\n        }\n    }\n\n    for (int H = 4; H <= 10; H++) {\n        for (int W = 4; W <= 10; W++) {\n            for (int corner = 0; corner < 4; corner++) {\n                Room room = make_room(corner, H, W);\n                RoomEval e = evaluate_room(room);\n                if (e.safeScore > bestSafeScore) {\n                    bestSafeScore = e.safeScore;\n                    bestSafe = room;\n                    bestSafeEval = e;\n                }\n            }\n        }\n    }\n\n    bool risky =\n        bestAggEval.insidePets > 0 ||\n        bestAggEval.insideDogs > 0 ||\n        bestAggEval.expandedPets >= 5 ||\n        bestAggEval.nearDoorDogs >= 9 ||\n        bestAggEval.sumBest >= 55 ||\n        bestAggEval.tasks >= 25;\n\n    if (risky) return bestSafe;\n    return bestAgg;\n}\n\nBFSRes bfs_from(pair<int,int> st, const array<array<bool, S>, S>& blocked) {\n    BFSRes res;\n    queue<pair<int,int>> q;\n    auto [sr, sc] = st;\n    res.dist[sr][sc] = 0;\n    res.first[sr][sc] = '.';\n    q.push(st);\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n        for (int k = 0; k < 4; k++) {\n            int nr = r + dr[k], nc = c + dc[k];\n            if (!inb(nr, nc)) continue;\n            if (blocked[nr][nc]) continue;\n            if (res.dist[nr][nc] != -1) continue;\n            res.dist[nr][nc] = res.dist[r][c] + 1;\n            res.first[nr][nc] = (res.dist[r][c] == 0 ? moveChar[k] : res.first[r][c]);\n            q.push({nr, nc});\n        }\n    }\n    return res;\n}\n\nvector<BFSRes> all_bfs(const array<array<bool, S>, S>& blocked) {\n    vector<BFSRes> v(M);\n    for (int i = 0; i < M; i++) v[i] = bfs_from(humansPos[i], blocked);\n    return v;\n}\n\nvoid rebuild_counts(array<array<int, S>, S>& humanCnt,\n                    array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            humanCnt[i][j] = 0;\n            petCnt[i][j] = 0;\n        }\n    }\n    for (auto [r, c] : humansPos) humanCnt[r][c]++;\n    for (auto [r, c] : petsPos) petCnt[r][c]++;\n}\n\nbool can_block_cell(int tr, int tc,\n                    const array<array<int, S>, S>& humanCnt,\n                    const array<array<int, S>, S>& petCnt) {\n    if (!inb(tr, tc)) return false;\n    if (humanCnt[tr][tc] > 0) return false;\n    if (petCnt[tr][tc] > 0) return false;\n    for (int k = 0; k < 4; k++) {\n        int nr = tr + dr[k], nc = tc + dc[k];\n        if (!inb(nr, nc)) continue;\n        if (petCnt[nr][nc] > 0) return false;\n    }\n    return true;\n}\n\nbool unfinished_exists(const Room& room) {\n    for (auto &t : room.tasks) {\n        if (!wallCell[t.wr][t.wc]) return true;\n    }\n    return false;\n}\n\nint pets_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : petsPos) if (room.inside(r, c)) cnt++;\n    return cnt;\n}\n\nint humans_inside_count(const Room& room) {\n    int cnt = 0;\n    for (auto [r, c] : humansPos) if (room.inside(r, c)) cnt++;\n    return cnt;\n}\n\nint required_inside_count(int turn) {\n    int dogCnt = count_dogs();\n    int req = M - (dogCnt > 0 ? 1 : 0);\n    if (turn >= 240) req = min(req, M - 1);\n    if (turn >= 285) req = min(req, M - 2);\n    return max(1, req);\n}\n\nbool should_close_final(int turn, int petsInside) {\n    if (petsInside == 0) return true;\n    if (turn >= 275 && petsInside <= 1) return true;\n    if (turn >= 292 && petsInside <= 2) return true;\n    if (turn >= 298) return true;\n    return false;\n}\n\npair<int,int> decoy_target(const Room& room) {\n    int tr = (room.r1 == 0 ? 24 : 5);\n    int tc = (room.c1 == 0 ? 24 : 5);\n    return {tr, tc};\n}\n\nint live_door_risk(const Door& d) {\n    int risk = 0;\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        int dist = abs(r - d.wr) + abs(c - d.wc);\n        if (dist == 0) risk += 100000;\n        else if (dist == 1) risk += 50000;\n        else if (dist <= 3) risk += (4 - dist) * 200;\n        if (petsType[i] == 4 && dist <= 6) risk += (7 - dist) * 80;\n    }\n    return risk;\n}\n\nint assign_to_target(const Room& room,\n                     const vector<BFSRes>& bfs,\n                     vector<bool>& used,\n                     string& act,\n                     int tr, int tc,\n                     bool preferInside) {\n    int best = -1, bestD = INF;\n\n    bool hasInsideCandidate = false;\n    if (preferInside) {\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            if (!room.inside(humansPos[i].first, humansPos[i].second)) continue;\n            int d = bfs[i].dist[tr][tc];\n            if (d >= 0) hasInsideCandidate = true;\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (used[i]) continue;\n        if (preferInside && hasInsideCandidate &&\n            !room.inside(humansPos[i].first, humansPos[i].second)) continue;\n        int d = bfs[i].dist[tr][tc];\n        if (d < 0) continue;\n        if (d < bestD) {\n            bestD = d;\n            best = i;\n        }\n    }\n\n    if (best != -1) {\n        used[best] = true;\n        if (bestD > 0) act[best] = bfs[best].first[tr][tc];\n    }\n    return best;\n}\n\nbool try_build_door_now(const Door& door,\n                        const array<array<int, S>, S>& humanCnt,\n                        const array<array<int, S>, S>& petCnt,\n                        vector<bool>& used,\n                        string& act) {\n    if (!can_block_cell(door.wr, door.wc, humanCnt, petCnt)) return false;\n    for (int i = 0; i < M; i++) {\n        if (used[i]) continue;\n        auto [r, c] = humansPos[i];\n        if (r == door.sr && c == door.sc) {\n            act[i] = door.act;\n            used[i] = true;\n            return true;\n        }\n    }\n    return false;\n}\n\nstring plan_build_actions(const Room& room,\n                          const array<array<int, S>, S>& humanCnt,\n                          const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n\n    vector<int> unfinished;\n    for (int i = 0; i < (int)room.tasks.size(); i++) {\n        auto &t = room.tasks[i];\n        if (!wallCell[t.wr][t.wc]) unfinished.push_back(i);\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    vector<bool> humanUsed(M, false);\n    vector<bool> taskUsed(room.tasks.size(), false);\n\n    for (int i = 0; i < M; i++) {\n        auto [hr, hc] = humansPos[i];\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                if (can_block_cell(t.wr, t.wc, humanCnt, petCnt) && !toBlock[t.wr][t.wc]) {\n                    act[i] = t.act;\n                    humanUsed[i] = true;\n                    taskUsed[idx] = true;\n                    toBlock[t.wr][t.wc] = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    array<array<bool, S>, S> blocked = wallCell;\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) blocked[i][j] = true;\n        }\n    }\n\n    vector<BFSRes> bfs = all_bfs(blocked);\n    vector<int> assignedTask(M, -1);\n\n    while (true) {\n        int bestH = -1, bestT = -1, bestD = INF;\n        for (int i = 0; i < M; i++) {\n            if (humanUsed[i]) continue;\n            for (int idx : unfinished) {\n                if (taskUsed[idx]) continue;\n                auto &t = room.tasks[idx];\n                int d = bfs[i].dist[t.sr][t.sc];\n                if (d <= 0) continue;\n                if (d < bestD) {\n                    bestD = d;\n                    bestH = i;\n                    bestT = idx;\n                }\n            }\n        }\n        if (bestH == -1) break;\n        humanUsed[bestH] = true;\n        taskUsed[bestT] = true;\n        assignedTask[bestH] = bestT;\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (assignedTask[i] != -1) {\n            auto &t = room.tasks[assignedTask[i]];\n            char mv = bfs[i].first[t.sr][t.sc];\n            if (mv) act[i] = mv;\n        }\n    }\n\n    for (int i = 0; i < M; i++) {\n        if (act[i] != '.') continue;\n        auto [hr, hc] = humansPos[i];\n\n        bool onSomeUnfinishedStance = false;\n        for (int idx : unfinished) {\n            if (taskUsed[idx]) continue;\n            auto &t = room.tasks[idx];\n            if (hr == t.sr && hc == t.sc) {\n                onSomeUnfinishedStance = true;\n                break;\n            }\n        }\n        if (onSomeUnfinishedStance) continue;\n\n        int d = bfs[i].dist[room.centerR][room.centerC];\n        if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n    }\n\n    return act;\n}\n\nstring plan_wait_actions(const Room& room, int turn,\n                         const array<array<int, S>, S>& humanCnt,\n                         const array<array<int, S>, S>& petCnt) {\n    string act(M, '.');\n    vector<bool> used(M, false);\n\n    array<array<bool, S>, S> blocked = wallCell;\n    vector<BFSRes> bfs = all_bfs(blocked);\n\n    vector<int> openDoors;\n    for (int d = 0; d < 2; d++) {\n        if (!wallCell[room.doors[d].wr][room.doors[d].wc]) openDoors.push_back(d);\n    }\n\n    int insideCnt = humans_inside_count(room);\n    int needInside = required_inside_count(turn);\n    int petsInside = pets_inside_count(room);\n    bool hasDog = (count_dogs() > 0);\n    auto [decoyR, decoyC] = decoy_target(room);\n\n    if ((int)openDoors.size() == 2) {\n        int d0 = openDoors[0], d1 = openDoors[1];\n        int risk0 = live_door_risk(room.doors[d0]);\n        int risk1 = live_door_risk(room.doors[d1]);\n\n        int keepDoor = (risk0 <= risk1 ? d0 : d1);\n        int closeDoor = (keepDoor == d0 ? d1 : d0);\n\n        int chosenClose = -1;\n        if (can_block_cell(room.doors[closeDoor].wr, room.doors[closeDoor].wc, humanCnt, petCnt)) {\n            chosenClose = closeDoor;\n        } else if (turn >= 240 &&\n                   can_block_cell(room.doors[keepDoor].wr, room.doors[keepDoor].wc, humanCnt, petCnt)) {\n            chosenClose = keepDoor;\n        }\n\n        if (chosenClose != -1) {\n            if (!try_build_door_now(room.doors[chosenClose], humanCnt, petCnt, used, act)) {\n                assign_to_target(room, bfs, used, act,\n                                 room.doors[chosenClose].sr, room.doors[chosenClose].sc,\n                                 true);\n            }\n        } else {\n            assign_to_target(room, bfs, used, act,\n                             room.doors[closeDoor].sr, room.doors[closeDoor].sc,\n                             true);\n        }\n\n        int futureMain = (chosenClose == -1 ? keepDoor : (chosenClose == keepDoor ? closeDoor : keepDoor));\n        if (turn >= 180 || insideCnt >= needInside) {\n            assign_to_target(room, bfs, used, act,\n                             room.doors[futureMain].sr, room.doors[futureMain].sc,\n                             true);\n        }\n\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            auto [r, c] = humansPos[i];\n            if (room.inside(r, c)) {\n                int d = bfs[i].dist[room.centerR][room.centerC];\n                if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n            } else {\n                if (insideCnt < needInside) {\n                    int d = bfs[i].dist[room.centerR][room.centerC];\n                    if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                } else if (hasDog) {\n                    int d = bfs[i].dist[decoyR][decoyC];\n                    if (d > 0) act[i] = bfs[i].first[decoyR][decoyC];\n                } else {\n                    int d = bfs[i].dist[room.centerR][room.centerC];\n                    if (d > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                }\n            }\n        }\n        return act;\n    }\n\n    if ((int)openDoors.size() == 1) {\n        int d = openDoors[0];\n        const Door& door = room.doors[d];\n\n        bool closeNow = (insideCnt >= needInside) &&\n                        should_close_final(turn, petsInside) &&\n                        can_block_cell(door.wr, door.wc, humanCnt, petCnt);\n\n        if (closeNow) {\n            if (!try_build_door_now(door, humanCnt, petCnt, used, act)) {\n                assign_to_target(room, bfs, used, act, door.sr, door.sc, true);\n            }\n        } else {\n            if (insideCnt >= needInside || petsInside == 0 || turn >= 220) {\n                assign_to_target(room, bfs, used, act, door.sr, door.sc, true);\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            if (used[i]) continue;\n            auto [r, c] = humansPos[i];\n            if (room.inside(r, c)) {\n                int dd = bfs[i].dist[room.centerR][room.centerC];\n                if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n            } else {\n                if (insideCnt < needInside) {\n                    int dd = bfs[i].dist[room.centerR][room.centerC];\n                    if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                } else if (hasDog) {\n                    int dd = bfs[i].dist[decoyR][decoyC];\n                    if (dd > 0) act[i] = bfs[i].first[decoyR][decoyC];\n                } else {\n                    int dd = bfs[i].dist[room.centerR][room.centerC];\n                    if (dd > 0) act[i] = bfs[i].first[room.centerR][room.centerC];\n                }\n            }\n        }\n        return act;\n    }\n\n    return act;\n}\n\nstring sanitize_actions(string act,\n                        const array<array<int, S>, S>& humanCnt,\n                        const array<array<int, S>, S>& petCnt) {\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_lower_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [tr, tc] = apply_dir({r, c}, a);\n        if (!can_block_cell(tr, tc, humanCnt, petCnt)) {\n            act[i] = '.';\n        }\n    }\n\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_lower_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [tr, tc] = apply_dir({r, c}, a);\n        if (inb(tr, tc)) toBlock[tr][tc] = true;\n    }\n\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (!is_upper_act(a)) continue;\n        auto [r, c] = humansPos[i];\n        auto [nr, nc] = apply_dir({r, c}, a);\n        if (!inb(nr, nc) || wallCell[nr][nc] || toBlock[nr][nc]) {\n            act[i] = '.';\n        }\n    }\n\n    return act;\n}\n\nvoid apply_human_actions(const string& act) {\n    array<array<bool, S>, S> toBlock{};\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) toBlock[i][j] = false;\n\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (is_lower_act(a)) {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc)) toBlock[nr][nc] = true;\n        }\n    }\n\n    for (int i = 0; i < S; i++) {\n        for (int j = 0; j < S; j++) {\n            if (toBlock[i][j]) wallCell[i][j] = true;\n        }\n    }\n\n    vector<pair<int,int>> newHumans = humansPos;\n    for (int i = 0; i < M; i++) {\n        char a = act[i];\n        if (is_upper_act(a)) {\n            auto [r, c] = humansPos[i];\n            auto [nr, nc] = apply_dir({r, c}, a);\n            if (inb(nr, nc) && !wallCell[nr][nc]) {\n                newHumans[i] = {nr, nc};\n            }\n        }\n    }\n    humansPos.swap(newHumans);\n}\n\nvoid apply_pet_moves(const vector<string>& petMoves) {\n    for (int i = 0; i < N; i++) {\n        auto [r, c] = petsPos[i];\n        for (char ch : petMoves[i]) {\n            if (ch == '.') continue;\n            auto [nr, nc] = apply_dir({r, c}, ch);\n            r = nr;\n            c = nc;\n        }\n        petsPos[i] = {r, c};\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    petsPos.resize(N);\n    petsType.resize(N);\n    for (int i = 0; i < N; i++) {\n        int x, y, t;\n        cin >> x >> y >> t;\n        --x; --y;\n        petsPos[i] = {x, y};\n        petsType[i] = t;\n    }\n\n    cin >> M;\n    humansPos.resize(M);\n    for (int i = 0; i < M; i++) {\n        int x, y;\n        cin >> x >> y;\n        --x; --y;\n        humansPos[i] = {x, y};\n    }\n\n    for (int i = 0; i < S; i++) for (int j = 0; j < S; j++) wallCell[i][j] = false;\n\n    Room room = choose_room();\n\n    for (int turn = 0; turn < MAX_TURN; turn++) {\n        array<array<int, S>, S> humanCnt, petCnt;\n        rebuild_counts(humanCnt, petCnt);\n\n        string act(M, '.');\n\n        bool fullyClosed =\n            wallCell[room.doors[0].wr][room.doors[0].wc] &&\n            wallCell[room.doors[1].wr][room.doors[1].wc];\n\n        if (fullyClosed) {\n            act = string(M, '.');\n        } else if (unfinished_exists(room)) {\n            act = plan_build_actions(room, humanCnt, petCnt);\n        } else {\n            act = plan_wait_actions(room, turn, humanCnt, petCnt);\n        }\n\n        act = sanitize_actions(act, humanCnt, petCnt);\n\n        cout << act << '\\n' << flush;\n\n        apply_human_actions(act);\n\n        vector<string> petMoves(N);\n        for (int i = 0; i < N; i++) {\n            if (!(cin >> petMoves[i])) return 0;\n        }\n        apply_pet_moves(petMoves);\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nconstexpr int N = 20;\nconstexpr int V = N * N;\nconstexpr int LMAX = 200;\nconstexpr int NONE = 4;\nconstexpr double EPS = 1e-12;\n\nconst char ACT[4] = {'U', 'D', 'L', 'R'};\nconst int prefDirOrder[4] = {1, 3, 0, 2}; // D, R, U, L\nconst int isUL[4] = {1, 0, 1, 0};\n\nint si, sj, ti, tj, sid, tid;\ndouble p_forget, p_move;\n\nstring H[N];\nstring VW[N - 1];\n\nint toCell[V][4];\nunsigned char transKind[V][4]; // 0: stay, 1: move, 2: hit target\nvector<int> neighbors[V];\n\nint distToT[V];\nbool spValid[V][4];\n\ndouble hitReward[LMAX + 1];\ndouble UB[LMAX + 2][V];\n\ndouble preDist[LMAX + 1][V];\ndouble sufVal[LMAX + 2][V];\ndouble prefScore[LMAX + 1];\ndouble aliveMass[LMAX + 1];\n\nint dpMinTurn[V][5];\nint dpMaxTurn[V][5];\n\ninline int ID(int i, int j) { return i * N + j; }\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t nextU64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\ninline double dot400(const double* a, const double* b) {\n    double s = 0.0;\n    for (int i = 0; i < V; i++) s += a[i] * b[i];\n    return s;\n}\n\ninline double dot400_arr(const array<double, V>& a, const double* b) {\n    double s = 0.0;\n    for (int i = 0; i < V; i++) s += a[i] * b[i];\n    return s;\n}\n\nvoid buildTransitions() {\n    for (int c = 0; c < V; c++) neighbors[c].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int c = ID(i, j);\n\n            // U\n            if (i > 0 && VW[i - 1][j] == '0') toCell[c][0] = ID(i - 1, j);\n            else toCell[c][0] = c;\n\n            // D\n            if (i < N - 1 && VW[i][j] == '0') toCell[c][1] = ID(i + 1, j);\n            else toCell[c][1] = c;\n\n            // L\n            if (j > 0 && H[i][j - 1] == '0') toCell[c][2] = ID(i, j - 1);\n            else toCell[c][2] = c;\n\n            // R\n            if (j < N - 1 && H[i][j] == '0') toCell[c][3] = ID(i, j + 1);\n            else toCell[c][3] = c;\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            int nc = toCell[c][a];\n            if (nc != c) neighbors[c].push_back(nc);\n        }\n        sort(neighbors[c].begin(), neighbors[c].end());\n        neighbors[c].erase(unique(neighbors[c].begin(), neighbors[c].end()), neighbors[c].end());\n    }\n\n    // Target absorbing for value DP\n    for (int a = 0; a < 4; a++) toCell[tid][a] = tid;\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c == tid) transKind[c][a] = 0;\n            else if (toCell[c][a] == c) transKind[c][a] = 0;\n            else if (toCell[c][a] == tid) transKind[c][a] = 2;\n            else transKind[c][a] = 1;\n        }\n    }\n}\n\nvoid bfsDistToTarget() {\n    fill(distToT, distToT + V, -1);\n    queue<int> q;\n    distToT[tid] = 0;\n    q.push(tid);\n\n    while (!q.empty()) {\n        int c = q.front();\n        q.pop();\n        for (int nc : neighbors[c]) {\n            if (distToT[nc] == -1) {\n                distToT[nc] = distToT[c] + 1;\n                q.push(nc);\n            }\n        }\n    }\n\n    for (int c = 0; c < V; c++) {\n        for (int a = 0; a < 4; a++) {\n            if (c != tid && transKind[c][a] != 0) {\n                int nc = toCell[c][a];\n                spValid[c][a] = (distToT[nc] == distToT[c] - 1);\n            } else {\n                spValid[c][a] = false;\n            }\n        }\n    }\n}\n\nvoid computeAdaptiveUpperBound() {\n    for (int c = 0; c < V; c++) UB[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        UB[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                double val;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    val = UB[t + 1][c];\n                } else if (k == 2) {\n                    val = hitReward[t] + p_forget * UB[t + 1][c];\n                } else {\n                    int nc = toCell[c][a];\n                    val = p_forget * UB[t + 1][c] + p_move * UB[t + 1][nc];\n                }\n                if (val > best) best = val;\n            }\n            UB[t][c] = best;\n        }\n    }\n}\n\nvector<int> rolloutFrom(const double* startDist, int prefixLen, bool stochastic, double temp, XorShift64& rng) {\n    int rem = LMAX - prefixLen;\n    vector<int> seq(rem, 0);\n    array<double, V> dist{};\n    for (int c = 0; c < V; c++) dist[c] = startDist[c];\n\n    for (int step = 0; step < rem; step++) {\n        int turn = prefixLen + step + 1; // 1-based\n        double val[4];\n        for (int a = 0; a < 4; a++) {\n            double cur = 0.0;\n            for (int c = 0; c < V; c++) {\n                double q = dist[c];\n                if (q < 1e-18) continue;\n                unsigned char k = transKind[c][a];\n                if (k == 0) {\n                    cur += q * UB[turn + 1][c];\n                } else if (k == 2) {\n                    cur += q * (hitReward[turn] + p_forget * UB[turn + 1][c]);\n                } else {\n                    int nc = toCell[c][a];\n                    cur += q * (p_forget * UB[turn + 1][c] + p_move * UB[turn + 1][nc]);\n                }\n            }\n            val[a] = cur;\n        }\n\n        int chosen = 0;\n        if (!stochastic) {\n            double bestVal = -1e100;\n            for (int kk = 0; kk < 4; kk++) {\n                int a = prefDirOrder[kk];\n                if (val[a] > bestVal + 1e-15) {\n                    bestVal = val[a];\n                    chosen = a;\n                }\n            }\n        } else {\n            double mx = max(max(val[0], val[1]), max(val[2], val[3]));\n            double w[4], sum = 0.0;\n            for (int a = 0; a < 4; a++) {\n                double z = (val[a] - mx) / temp;\n                w[a] = (z < -50.0 ? 0.0 : exp(z));\n                sum += w[a];\n            }\n            if (sum <= 0.0) {\n                chosen = prefDirOrder[rng.nextInt(4)];\n            } else {\n                double r = rng.nextDouble() * sum;\n                double acc = 0.0;\n                for (int kk = 0; kk < 4; kk++) {\n                    int a = prefDirOrder[kk];\n                    acc += w[a];\n                    if (r <= acc) {\n                        chosen = a;\n                        break;\n                    }\n                }\n            }\n        }\n\n        seq[step] = chosen;\n\n        array<double, V> nd{};\n        nd.fill(0.0);\n        for (int c = 0; c < V; c++) {\n            double q = dist[c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][chosen];\n            if (k == 0) {\n                nd[c] += q;\n            } else if (k == 2) {\n                nd[c] += q * p_forget;\n            } else {\n                int nc = toCell[c][chosen];\n                nd[c] += q * p_forget;\n                nd[nc] += q * p_move;\n            }\n        }\n        dist = nd;\n    }\n\n    return seq;\n}\n\nvector<int> greedyLikeRollout(bool stochastic, double temp, XorShift64& rng) {\n    static double start[V];\n    fill(start, start + V, 0.0);\n    start[sid] = 1.0;\n    return rolloutFrom(start, 0, stochastic, temp, rng);\n}\n\nstruct CurState {\n    array<double, V> dist;\n    double score;\n};\n\nstruct CandState {\n    array<double, V> dist;\n    double score;\n    double pri;\n    int parent;\n    unsigned char act;\n};\n\nstruct ParentInfo {\n    int parent;\n    unsigned char act;\n};\n\nvector<vector<int>> beamSearchFrom(const double* startDist, int prefixLen, int beamWidth, int topM) {\n    int rem = LMAX - prefixLen;\n    vector<vector<ParentInfo>> parent(rem + 1);\n\n    vector<CurState> cur, nxt;\n    cur.reserve(beamWidth);\n    nxt.reserve(beamWidth);\n\n    CurState root;\n    root.dist.fill(0.0);\n    for (int c = 0; c < V; c++) root.dist[c] = startDist[c];\n    root.score = 0.0;\n    cur.push_back(root);\n\n    vector<CandState> cand;\n    cand.reserve(beamWidth * 4);\n    vector<int> ord;\n\n    for (int d = 0; d < rem; d++) {\n        int turn = prefixLen + d + 1;\n        cand.clear();\n\n        for (int idx = 0; idx < (int)cur.size(); idx++) {\n            const auto& st = cur[idx];\n            for (int a = 0; a < 4; a++) {\n                CandState cs;\n                cs.dist.fill(0.0);\n                cs.parent = idx;\n                cs.act = (unsigned char)a;\n                double scoreAfter = st.score;\n                double pri = st.score;\n\n                for (int c = 0; c < V; c++) {\n                    double q = st.dist[c];\n                    if (q < 1e-18) continue;\n                    unsigned char k = transKind[c][a];\n                    if (k == 0) {\n                        cs.dist[c] += q;\n                        pri += q * UB[turn + 1][c];\n                    } else if (k == 2) {\n                        cs.dist[c] += q * p_forget;\n                        scoreAfter += q * hitReward[turn];\n                        pri += q * (hitReward[turn] + p_forget * UB[turn + 1][c]);\n                    } else {\n                        int nc = toCell[c][a];\n                        cs.dist[c] += q * p_forget;\n                        cs.dist[nc] += q * p_move;\n                        pri += q * (p_forget * UB[turn + 1][c] + p_move * UB[turn + 1][nc]);\n                    }\n                }\n\n                cs.score = scoreAfter;\n                cs.pri = pri;\n                cand.push_back(std::move(cs));\n            }\n        }\n\n        int k = min(beamWidth, (int)cand.size());\n        ord.resize(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n\n        auto cmp = [&](int x, int y) {\n            if (cand[x].pri != cand[y].pri) return cand[x].pri > cand[y].pri;\n            if (cand[x].score != cand[y].score) return cand[x].score > cand[y].score;\n            if (cand[x].parent != cand[y].parent) return cand[x].parent < cand[y].parent;\n            return cand[x].act < cand[y].act;\n        };\n        partial_sort(ord.begin(), ord.begin() + k, ord.end(), cmp);\n\n        nxt.clear();\n        parent[d + 1].resize(k);\n        for (int i = 0; i < k; i++) {\n            int id = ord[i];\n            CurState ns;\n            ns.dist = cand[id].dist;\n            ns.score = cand[id].score;\n            nxt.push_back(std::move(ns));\n            parent[d + 1][i] = ParentInfo{cand[id].parent, cand[id].act};\n        }\n        cur.swap(nxt);\n    }\n\n    vector<int> finalOrd(cur.size());\n    iota(finalOrd.begin(), finalOrd.end(), 0);\n    sort(finalOrd.begin(), finalOrd.end(), [&](int x, int y) {\n        if (cur[x].score != cur[y].score) return cur[x].score > cur[y].score;\n        return x < y;\n    });\n\n    topM = min(topM, (int)finalOrd.size());\n    vector<vector<int>> res;\n    for (int z = 0; z < topM; z++) {\n        int idx = finalOrd[z];\n        vector<int> suf(rem);\n        for (int d = rem; d >= 1; d--) {\n            suf[d - 1] = parent[d][idx].act;\n            idx = parent[d][idx].parent;\n        }\n        res.push_back(std::move(suf));\n    }\n    return res;\n}\n\nvector<vector<int>> beamSearch(int beamWidth, int topM) {\n    static double start[V];\n    fill(start, start + V, 0.0);\n    start[sid] = 1.0;\n    return beamSearchFrom(start, 0, beamWidth, topM);\n}\n\nvector<int> buildShortestPathByTurns(bool maximizeTurns) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return distToT[a] < distToT[b];\n    });\n\n    const int INF = 1e9;\n\n    for (int c : ids) {\n        for (int last = 0; last < 5; last++) {\n            if (c == tid) {\n                dpMinTurn[c][last] = 0;\n                dpMaxTurn[c][last] = 0;\n                continue;\n            }\n\n            int bestMin = INF;\n            int bestMax = -INF;\n\n            for (int a = 0; a < 4; a++) {\n                if (!spValid[c][a]) continue;\n                int nc = toCell[c][a];\n                int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n                bestMin = min(bestMin, turnCost + isUL[a] + dpMinTurn[nc][a]);\n                bestMax = max(bestMax, turnCost - isUL[a] + dpMaxTurn[nc][a]);\n            }\n\n            dpMinTurn[c][last] = bestMin;\n            dpMaxTurn[c][last] = bestMax;\n        }\n    }\n\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n\n    while (c != tid) {\n        int bestA = -1;\n        int bestVal = maximizeTurns ? -INF : INF;\n\n        for (int kk = 0; kk < 4; kk++) {\n            int a = prefDirOrder[kk];\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            int turnCost = (last != NONE && last != a) ? 1000 : 0;\n\n            int val;\n            if (maximizeTurns) {\n                val = turnCost - isUL[a] + dpMaxTurn[nc][a];\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            } else {\n                val = turnCost + isUL[a] + dpMinTurn[nc][a];\n                if (val < bestVal) {\n                    bestVal = val;\n                    bestA = a;\n                }\n            }\n        }\n\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n\n    return path;\n}\n\nvector<int> repeatPathTo200(const vector<int>& path) {\n    vector<int> seq(LMAX, 1);\n    if (path.empty()) return seq;\n    for (int t = 0; t < LMAX; t++) seq[t] = path[t % (int)path.size()];\n    return seq;\n}\n\nvector<int> inflateAndRepeat(const vector<int>& path, int rep) {\n    vector<int> ext;\n    if (path.empty()) return vector<int>(LMAX, 1);\n    ext.reserve((int)path.size() * rep);\n    for (int a : path) for (int r = 0; r < rep; r++) ext.push_back(a);\n    return repeatPathTo200(ext);\n}\n\nvector<int> makePeriodic(const vector<int>& pat) {\n    vector<int> seq(LMAX);\n    for (int t = 0; t < LMAX; t++) seq[t] = pat[t % (int)pat.size()];\n    return seq;\n}\n\nvector<int> randomWeightedShortestPath(XorShift64& rng, double wTurn, double wBlock, double noise) {\n    vector<int> path;\n    int c = sid;\n    int last = NONE;\n    while (c != tid) {\n        int bestA = -1;\n        double bestS = -1e100;\n\n        for (int a = 0; a < 4; a++) {\n            if (!spValid[c][a]) continue;\n            int nc = toCell[c][a];\n            double s = 0.0;\n            if (last != NONE && last != a) s += wTurn;\n            if (nc == tid || toCell[nc][a] == nc) s += wBlock;\n            s += noise * rng.nextDouble();\n            if (s > bestS) {\n                bestS = s;\n                bestA = a;\n            }\n        }\n\n        if (bestA == -1) break;\n        path.push_back(bestA);\n        c = toCell[c][bestA];\n        last = bestA;\n    }\n    return path;\n}\n\nvoid computeForward(const vector<int>& seq) {\n    fill(preDist[0], preDist[0] + V, 0.0);\n    preDist[0][sid] = 1.0;\n    prefScore[0] = 0.0;\n    aliveMass[0] = 1.0;\n\n    for (int t = 1; t <= LMAX; t++) {\n        fill(preDist[t], preDist[t] + V, 0.0);\n        int a = seq[t - 1];\n        double sc = prefScore[t - 1];\n\n        for (int c = 0; c < V; c++) {\n            double q = preDist[t - 1][c];\n            if (q < 1e-18) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                preDist[t][c] += q;\n            } else if (k == 2) {\n                preDist[t][c] += q * p_forget;\n                sc += q * hitReward[t];\n            } else {\n                int nc = toCell[c][a];\n                preDist[t][c] += q * p_forget;\n                preDist[t][nc] += q * p_move;\n            }\n        }\n\n        prefScore[t] = sc;\n        double alive = 0.0;\n        for (int c = 0; c < V; c++) alive += preDist[t][c];\n        aliveMass[t] = alive;\n    }\n}\n\nvoid computeBackward(const vector<int>& seq) {\n    for (int c = 0; c < V; c++) sufVal[LMAX + 1][c] = 0.0;\n\n    for (int t = LMAX; t >= 1; t--) {\n        int a = seq[t - 1];\n        sufVal[t][tid] = 0.0;\n        for (int c = 0; c < V; c++) {\n            if (c == tid) continue;\n            unsigned char k = transKind[c][a];\n            if (k == 0) {\n                sufVal[t][c] = sufVal[t + 1][c];\n            } else if (k == 2) {\n                sufVal[t][c] = hitReward[t] + p_forget * sufVal[t + 1][c];\n            } else {\n                int nc = toCell[c][a];\n                sufVal[t][c] = p_forget * sufVal[t + 1][c] + p_move * sufVal[t + 1][nc];\n            }\n        }\n    }\n}\n\ndouble exactScore(const vector<int>& seq) {\n    computeForward(seq);\n    return prefScore[LMAX];\n}\n\ninline void applyActionValue(int pos, int a, const double* next, double* out) {\n    out[tid] = 0.0;\n    for (int c = 0; c < V; c++) {\n        if (c == tid) continue;\n        unsigned char k = transKind[c][a];\n        if (k == 0) {\n            out[c] = next[c];\n        } else if (k == 2) {\n            out[c] = hitReward[pos] + p_forget * next[c];\n        } else {\n            int nc = toCell[c][a];\n            out[c] = p_forget * next[c] + p_move * next[nc];\n        }\n    }\n}\n\nstruct Change {\n    int k = 0;\n    int pos = -1;\n    int a[4] = {0, 0, 0, 0};\n    double score = -1e100;\n};\n\nChange searchBest1(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double out[V];\n\n    for (int t = 1; t <= LMAX; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n        const double* nxt = sufVal[t + 1];\n\n        for (int a = 0; a < 4; a++) {\n            if (a == seq[t - 1]) continue;\n            applyActionValue(t, a, nxt, out);\n            double val = base + dot400(pre, out);\n            if (val > best.score + EPS) {\n                best.score = val;\n                best.k = 1;\n                best.pos = t - 1;\n                best.a[0] = a;\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest2(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double mid[4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 1; t++) {\n        if ((t & 15) == 0 && Clock::now() >= deadline) break;\n        for (int b = 0; b < 4; b++) applyActionValue(t + 1, b, sufVal[t + 2], mid[b]);\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                if (a == seq[t - 1] && b == seq[t]) continue;\n                applyActionValue(t, a, mid[b], out);\n                double val = base + dot400(pre, out);\n                if (val > best.score + EPS) {\n                    best.score = val;\n                    best.k = 2;\n                    best.pos = t - 1;\n                    best.a[0] = a;\n                    best.a[1] = b;\n                }\n            }\n        }\n    }\n    return best;\n}\n\nChange searchBest3(const vector<int>& seq, double curScore, const Clock::time_point& deadline) {\n    Change best;\n    best.score = curScore;\n    static double tail[4][V];\n    static double mid[4][4][V];\n    static double out[V];\n\n    for (int t = 1; t <= LMAX - 2; t++) {\n        if ((t & 7) == 0 && Clock::now() >= deadline) break;\n\n        for (int c = 0; c < 4; c++) applyActionValue(t + 2, c, sufVal[t + 3], tail[c]);\n        for (int b = 0; b < 4; b++) {\n            for (int c = 0; c < 4; c++) {\n                applyActionValue(t + 1, b, tail[c], mid[b][c]);\n            }\n        }\n\n        const double* pre = preDist[t - 1];\n        double base = prefScore[t - 1];\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                for (int c = 0; c < 4; c++) {\n                    if (a == seq[t - 1] && b == seq[t] && c == seq[t + 1]) continue;\n                    applyActionValue(t, a, mid[b][c], out);\n                    double val = base + dot400(pre, out);\n                    if (val > best.score + EPS) {\n                        best.score = val;\n                        best.k = 3;\n                        best.pos = t - 1;\n                        best.a[0] = a;\n                        best.a[1] = b;\n                        best.a[2] = c;\n                    }\n                }\n            }\n        }\n    }\n    return best;\n}\n\ndouble localDescent(vector<int>& seq, const Clock::time_point& deadline, int maxIter, bool allow3) {\n    computeForward(seq);\n    double curScore = prefScore[LMAX];\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (Clock::now() >= deadline) break;\n        computeBackward(seq);\n\n        Change best = searchBest1(seq, curScore, deadline);\n        if (Clock::now() >= deadline) break;\n\n        Change c2 = searchBest2(seq, curScore, deadline);\n        if (c2.score > best.score + EPS) best = c2;\n\n        if (allow3 && best.k == 0 && iter < 5) {\n            if (Clock::now() + chrono::milliseconds(40) < deadline) {\n                Change c3 = searchBest3(seq, curScore, deadline);\n                if (c3.score > best.score + EPS) best = c3;\n            }\n        }\n\n        if (best.k == 0) break;\n\n        for (int i = 0; i < best.k; i++) seq[best.pos + i] = best.a[i];\n        computeForward(seq);\n        curScore = prefScore[LMAX];\n    }\n\n    return curScore;\n}\n\nstruct WindowChange {\n    int pos = -1;\n    double score = -1e100;\n    int a[4] = {0, 0, 0, 0};\n};\n\nWindowChange searchBestWindow4Exact(const vector<int>& seq, double curScore, int topPos, const Clock::time_point& deadline) {\n    WindowChange best;\n    best.score = curScore;\n\n    vector<pair<double, int>> posCand;\n    posCand.reserve(LMAX);\n\n    for (int s = 0; s + 4 <= LMAX; s++) {\n        if (aliveMass[s] < 1e-9) continue;\n        double gap = 0.0;\n        for (int c = 0; c < V; c++) {\n            double q = preDist[s][c];\n            if (q < 1e-18) continue;\n            gap += q * (UB[s + 1][c] - sufVal[s + 1][c]);\n        }\n        if (gap > 1e-9) posCand.push_back({gap, s});\n    }\n\n    sort(posCand.begin(), posCand.end(), [&](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n    if ((int)posCand.size() > topPos) posCand.resize(topPos);\n\n    static double lv1[4][V];\n    static double lv2[4][4][V];\n    static double lv3[4][4][4][V];\n    static double out[V];\n\n    for (int idx = 0; idx < (int)posCand.size(); idx++) {\n        if ((idx & 3) == 0 && Clock::now() >= deadline) break;\n\n        int s = posCand[idx].second;\n        const double* pre = preDist[s];\n        double base = prefScore[s];\n\n        for (int d = 0; d < 4; d++) applyActionValue(s + 4, d, sufVal[s + 5], lv1[d]);\n        for (int c = 0; c < 4; c++) {\n            for (int d = 0; d < 4; d++) {\n                applyActionValue(s + 3, c, lv1[d], lv2[c][d]);\n            }\n        }\n        for (int b = 0; b < 4; b++) {\n            for (int c = 0; c < 4; c++) {\n                for (int d = 0; d < 4; d++) {\n                    applyActionValue(s + 2, b, lv2[c][d], lv3[b][c][d]);\n                }\n            }\n        }\n\n        for (int a = 0; a < 4; a++) {\n            for (int b = 0; b < 4; b++) {\n                for (int c = 0; c < 4; c++) {\n                    for (int d = 0; d < 4; d++) {\n                        if (a == seq[s] && b == seq[s + 1] && c == seq[s + 2] && d == seq[s + 3]) continue;\n                        applyActionValue(s + 1, a, lv3[b][c][d], out);\n                        double val = base + dot400(pre, out);\n                        if (val > best.score + EPS) {\n                            best.score = val;\n                            best.pos = s;\n                            best.a[0] = a;\n                            best.a[1] = b;\n                            best.a[2] = c;\n                            best.a[3] = d;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    return best;\n}\n\nstruct CutInfo {\n    int s;\n    array<double, V> dist;\n};\n\nvector<CutInfo> selectPromisingCuts(int need) {\n    vector<pair<double, int>> cand;\n    cand.reserve(LMAX);\n\n    for (int s = 8; s <= LMAX - 12; s++) {\n        if (aliveMass[s] < 1e-6) continue;\n        double gap = 0.0;\n        for (int c = 0; c < V; c++) {\n            double q = preDist[s][c];\n            if (q < 1e-18) continue;\n            gap += q * (UB[s + 1][c] - sufVal[s + 1][c]);\n        }\n        if (gap <= 1e-10) continue;\n        double score = gap * (0.35 + 0.65 * (double)s / LMAX);\n        cand.push_back({score, s});\n    }\n\n    sort(cand.begin(), cand.end(), [&](const auto& x, const auto& y) {\n        if (x.first != y.first) return x.first > y.first;\n        return x.second < y.second;\n    });\n\n    vector<CutInfo> res;\n    for (auto [score, s] : cand) {\n        bool ok = true;\n        for (auto& ci : res) {\n            if (abs(ci.s - s) < 12) {\n                ok = false;\n                break;\n            }\n        }\n        if (!ok) continue;\n        CutInfo ci;\n        ci.s = s;\n        for (int c = 0; c < V; c++) ci.dist[c] = preDist[s][c];\n        res.push_back(ci);\n        if ((int)res.size() >= need) break;\n    }\n    return res;\n}\n\ndouble trySuffixReplan(vector<int>& seq, double curScore, const Clock::time_point& deadline, bool heavy, XorShift64& rng) {\n    computeForward(seq);\n    computeBackward(seq);\n\n    auto cuts = selectPromisingCuts(heavy ? 3 : 1);\n    if (cuts.empty()) return curScore;\n\n    vector<int> bestSeq = seq;\n    double bestScore = curScore;\n\n    for (int idx = 0; idx < (int)cuts.size(); idx++) {\n        if (Clock::now() + chrono::milliseconds(25) >= deadline) break;\n\n        int s = cuts[idx].s;\n        const double* dist = cuts[idx].dist.data();\n\n        // Deterministic suffix rollout\n        {\n            vector<int> cand = seq;\n            auto suf = rolloutFrom(dist, s, false, 1.0, rng);\n            for (int i = 0; i < (int)suf.size(); i++) cand[s + i] = suf[i];\n            double sc = exactScore(cand);\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = std::move(cand);\n            }\n        }\n\n        // One stochastic suffix rollout\n        if ((heavy || idx == 0) && Clock::now() + chrono::milliseconds(20) < deadline) {\n            vector<int> cand = seq;\n            auto suf = rolloutFrom(dist, s, true, heavy ? 4.0 : 6.0, rng);\n            for (int i = 0; i < (int)suf.size(); i++) cand[s + i] = suf[i];\n            double sc = exactScore(cand);\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = std::move(cand);\n            }\n        }\n\n        // Small beam suffix\n        if ((heavy || idx == 0) && Clock::now() + chrono::milliseconds(30) < deadline) {\n            auto beams = beamSearchFrom(dist, s, heavy ? 28 : 18, 1);\n            for (auto& suf : beams) {\n                vector<int> cand = seq;\n                for (int i = 0; i < (int)suf.size(); i++) cand[s + i] = suf[i];\n                double sc = exactScore(cand);\n                if (sc > bestScore + EPS) {\n                    bestScore = sc;\n                    bestSeq = std::move(cand);\n                }\n            }\n        }\n    }\n\n    if (bestScore > curScore + EPS) {\n        seq = std::move(bestSeq);\n        curScore = localDescent(seq, deadline, heavy ? 6 : 3, false);\n    }\n    return curScore;\n}\n\ndouble improveSequence(vector<int>& seq, const Clock::time_point& deadline, bool heavy, XorShift64& rng) {\n    double sc = localDescent(seq, deadline, heavy ? 18 : 8, heavy);\n\n    // Small exact 4-window\n    if (Clock::now() + chrono::milliseconds(35) < deadline) {\n        computeForward(seq);\n        computeBackward(seq);\n        WindowChange wc = searchBestWindow4Exact(seq, sc, heavy ? 8 : 4, deadline);\n        if (wc.pos != -1 && wc.score > sc + EPS) {\n            for (int i = 0; i < 4; i++) seq[wc.pos + i] = wc.a[i];\n            sc = localDescent(seq, deadline, heavy ? 6 : 3, false);\n        }\n    }\n\n    // Suffix replanning from promising cut points\n    if (Clock::now() + chrono::milliseconds(40) < deadline) {\n        sc = trySuffixReplan(seq, sc, deadline, heavy, rng);\n    }\n\n    return sc;\n}\n\nstring seqToString(const vector<int>& seq) {\n    string s;\n    s.reserve(seq.size());\n    for (int a : seq) s.push_back(ACT[a]);\n    return s;\n}\n\nvoid perturb(vector<int>& seq, const vector<vector<int>>& pool, XorShift64& rng) {\n    int mode = rng.nextInt(4);\n\n    if (mode == 0) {\n        int len = 1 + rng.nextInt(8);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[pos + i] = rng.nextInt(4);\n    } else if (mode == 1 && !pool.empty()) {\n        int len = 5 + rng.nextInt(26);\n        len = min(len, LMAX);\n        int dst = rng.nextInt(LMAX - len + 1);\n        const auto& src = pool[rng.nextInt((int)pool.size())];\n        int srcPos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) seq[dst + i] = src[srcPos + i];\n    } else if (mode == 2) {\n        int cnt = 2 + rng.nextInt(5);\n        for (int k = 0; k < cnt; k++) {\n            int pos = rng.nextInt(LMAX);\n            seq[pos] = rng.nextInt(4);\n        }\n    } else {\n        int len = 3 + rng.nextInt(12);\n        int pos = rng.nextInt(LMAX - len + 1);\n        for (int i = 0; i < len; i++) {\n            if (rng.nextInt(3) == 0) seq[pos + i] = rng.nextInt(4);\n        }\n    }\n}\n\nuint64_t makeSeed() {\n    uint64_t seed = 1469598103934665603ULL;\n    auto mix = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mix(si); mix(sj); mix(ti); mix(tj);\n    mix((uint64_t)llround(p_forget * 1000.0));\n    for (int i = 0; i < N; i++) for (char ch : H[i]) mix((uint64_t)ch);\n    for (int i = 0; i < N - 1; i++) for (char ch : VW[i]) mix((uint64_t)ch);\n    return seed;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto globalStart = Clock::now();\n    auto deadline = globalStart + chrono::milliseconds(1930);\n\n    cin >> si >> sj >> ti >> tj >> p_forget;\n    for (int i = 0; i < N; i++) cin >> H[i];\n    for (int i = 0; i < N - 1; i++) cin >> VW[i];\n\n    sid = ID(si, sj);\n    tid = ID(ti, tj);\n    p_move = 1.0 - p_forget;\n\n    for (int t = 1; t <= LMAX; t++) hitReward[t] = p_move * (401 - t);\n\n    buildTransitions();\n    bfsDistToTarget();\n    computeAdaptiveUpperBound();\n\n    XorShift64 rng(makeSeed());\n\n    vector<vector<int>> candidates;\n    candidates.reserve(48);\n\n    // Rollout seeds\n    candidates.push_back(greedyLikeRollout(false, 1.0, rng));\n    candidates.push_back(greedyLikeRollout(true, 2.5, rng));\n    candidates.push_back(greedyLikeRollout(true, 5.0, rng));\n    candidates.push_back(greedyLikeRollout(true, 10.0, rng));\n\n    // Beam seeds\n    {\n        auto beams = beamSearch(84, 3);\n        for (auto& s : beams) candidates.push_back(s);\n    }\n\n    // Shortest-path style seeds\n    auto minTurnPath = buildShortestPathByTurns(false);\n    auto maxTurnPath = buildShortestPathByTurns(true);\n    candidates.push_back(repeatPathTo200(minTurnPath));\n    candidates.push_back(repeatPathTo200(maxTurnPath));\n    candidates.push_back(inflateAndRepeat(minTurnPath, 2));\n    candidates.push_back(inflateAndRepeat(maxTurnPath, 2));\n\n    // Randomized shortest-path variants\n    {\n        vector<tuple<double, double, double>> params = {\n            {-3.0, 0.0, 0.8},\n            { 3.0, 0.0, 0.8},\n            {-1.0, 2.0, 0.8},\n            { 1.0, 2.0, 0.8},\n            { 0.0, 3.0, 0.8},\n            {-2.0, 1.0, 1.5},\n            { 2.0, 1.0, 1.5},\n            { 0.0, 0.0, 2.0}\n        };\n        for (auto [wt, wb, nz] : params) {\n            auto pth = randomWeightedShortestPath(rng, wt, wb, nz);\n            candidates.push_back(repeatPathTo200(pth));\n        }\n    }\n\n    // Periodic robust baselines\n    candidates.push_back(makePeriodic({1, 3}));         // DRDR...\n    candidates.push_back(makePeriodic({3, 1}));         // RDRD...\n    candidates.push_back(makePeriodic({1, 1, 3, 3}));   // DDRR...\n    candidates.push_back(makePeriodic({3, 3, 1, 1}));   // RRDD...\n    candidates.push_back(makePeriodic({1, 3, 1, 3, 1}));\n\n    // Dedup\n    unordered_set<string> seen;\n    vector<vector<int>> uniq;\n    uniq.reserve(candidates.size());\n    for (auto& seq : candidates) {\n        string key = seqToString(seq);\n        if (seen.insert(key).second) uniq.push_back(seq);\n    }\n\n    // Initial exact ranking\n    vector<pair<double, int>> order;\n    order.reserve(uniq.size());\n    for (int i = 0; i < (int)uniq.size(); i++) {\n        double sc = exactScore(uniq[i]);\n        order.push_back({sc, i});\n    }\n    sort(order.begin(), order.end(), greater<pair<double, int>>());\n\n    vector<int> bestSeq = uniq[order[0].second];\n    double bestScore = order[0].first;\n\n    vector<vector<int>> pool;\n    for (int z = 0; z < (int)order.size() && z < 10; z++) {\n        pool.push_back(uniq[order[z].second]);\n    }\n\n    // Improve top seeds\n    int topTrials = min(5, (int)order.size());\n    for (int z = 0; z < topTrials; z++) {\n        if (Clock::now() >= deadline) break;\n        vector<int> seq = uniq[order[z].second];\n        double sc = improveSequence(seq, deadline, z < 2, rng);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n        if ((int)pool.size() < 18) pool.push_back(seq);\n    }\n\n    // Extra polish on current best\n    if (Clock::now() + chrono::milliseconds(80) < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = improveSequence(seq, deadline, true, rng);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    // Perturb + restart\n    while (Clock::now() + chrono::milliseconds(70) < deadline) {\n        vector<int> seq;\n        if (!pool.empty() && rng.nextInt(100) < 35) {\n            seq = pool[rng.nextInt(min<int>((int)pool.size(), 8))];\n        } else {\n            seq = bestSeq;\n        }\n\n        perturb(seq, pool, rng);\n        double sc = improveSequence(seq, deadline, false, rng);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n            if ((int)pool.size() < 20) pool.push_back(seq);\n        } else if ((int)pool.size() < 20 && sc + 0.02 >= bestScore) {\n            pool.push_back(seq);\n        }\n    }\n\n    // Final polish\n    if (Clock::now() < deadline) {\n        vector<int> seq = bestSeq;\n        double sc = improveSequence(seq, deadline, true, rng);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = seq;\n        }\n    }\n\n    cout << seqToString(bestSeq) << '\\n';\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int P = N * N;\nstatic constexpr int V = P * 4;\n\nstatic constexpr int DIR_L = 0;\nstatic constexpr int DIR_U = 1;\nstatic constexpr int DIR_R = 2;\nstatic constexpr int DIR_D = 3;\n\nstatic constexpr int opp[4] = {2, 3, 0, 1};\n\nstatic constexpr int MATCH_REWARD = 2;\nstatic constexpr int BROKEN_PENALTY = -3;\nstatic constexpr int BOUNDARY_PENALTY = -3;\n\nstatic constexpr long long SCORE_FACTOR = 10000000000LL;\nstatic constexpr long long L2_FACTOR = 1000000LL;\nstatic constexpr long long L1_FACTOR = 100LL;\n\nusing StateArray = array<uint8_t, P>;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ULL) : x(seed ? seed : 1) {}\n    inline uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    inline int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    inline double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct CycleEval {\n    int L1 = 0;\n    int L2 = 0;\n    int total = 0;\n    int numCycles = 0;\n    long long score = 0;\n    long long scalarNoG = LLONG_MIN / 4;\n};\n\nstruct Eval {\n    int g = 0;\n    CycleEval c;\n    long long scalar = LLONG_MIN / 4;\n};\n\nstruct Candidate {\n    StateArray st{};\n    Eval ev;\n};\n\nstatic const int TO[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\nstatic chrono::steady_clock::time_point g_start;\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ntemplate <class T>\nvoid shuffle_vec(vector<T>& v, RNG& rng) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.next_int(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nuint8_t activeMask[8];\nuint8_t stateToRot[8][8];\nuint8_t allowedState[P][4];\nuint8_t allowedCnt[P];\nuint8_t baseTile[P];\nbool isDoublePos[P];\nint16_t neighborPos[P][4];\n\nvector<int> allPos;\nvector<int> nonDoublePos;\nvector<int> doublePos;\nvector<array<int, 4>> blocks2x2;\nvector<array<int, 6>> windows23;\n\nint seenStampCell[P];\nint curStampCell = 1;\nint seenStampBlock[(N - 1) * (N - 1)];\nint curStampBlock = 1;\n\ninline long long make_scalar(const CycleEval& c, int g) {\n    return c.score * SCORE_FACTOR\n         + 1LL * c.L2 * L2_FACTOR\n         + 1LL * c.L1 * L1_FACTOR\n         + 2LL * c.total\n         + g;\n}\n\ninline Eval make_eval(int g, const CycleEval& c) {\n    Eval e;\n    e.g = g;\n    e.c = c;\n    e.scalar = make_scalar(c, g);\n    return e;\n}\n\ninline int rotate_state(int b, int r) {\n    if (b <= 3) return (b + r) & 3;\n    if (b <= 5) return 4 + ((b - 4 + r) & 1);\n    return 6 + ((b - 6 + r) & 1);\n}\n\nvoid init_tables() {\n    for (int s = 0; s < 8; s++) {\n        uint8_t mask = 0;\n        for (int d = 0; d < 4; d++) {\n            if (TO[s][d] != -1) mask |= uint8_t(1u << d);\n        }\n        activeMask[s] = mask;\n    }\n\n    for (int b = 0; b < 8; b++) {\n        for (int s = 0; s < 8; s++) stateToRot[b][s] = 255;\n        for (int r = 0; r < 4; r++) {\n            int s = rotate_state(b, r);\n            stateToRot[b][s] = min<int>(stateToRot[b][s], r);\n        }\n    }\n\n    allPos.reserve(P);\n    nonDoublePos.reserve(P);\n    doublePos.reserve(P);\n    blocks2x2.reserve((N - 1) * (N - 1));\n    windows23.reserve((N - 1) * (N - 2) * 2);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            neighborPos[p][DIR_L] = (j > 0 ? p - 1 : -1);\n            neighborPos[p][DIR_U] = (i > 0 ? p - N : -1);\n            neighborPos[p][DIR_R] = (j + 1 < N ? p + 1 : -1);\n            neighborPos[p][DIR_D] = (i + 1 < N ? p + N : -1);\n        }\n    }\n\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j + 1 < N; j++) {\n            blocks2x2.push_back({i * N + j, i * N + (j + 1), (i + 1) * N + j, (i + 1) * N + (j + 1)});\n        }\n    }\n\n    for (int i = 0; i + 1 < N; i++) {\n        for (int j = 0; j + 2 < N; j++) {\n            windows23.push_back({\n                i * N + j, i * N + (j + 1), i * N + (j + 2),\n                (i + 1) * N + j, (i + 1) * N + (j + 1), (i + 1) * N + (j + 2)\n            });\n        }\n    }\n    for (int i = 0; i + 2 < N; i++) {\n        for (int j = 0; j + 1 < N; j++) {\n            windows23.push_back({\n                i * N + j, i * N + (j + 1),\n                (i + 1) * N + j, (i + 1) * N + (j + 1),\n                (i + 2) * N + j, (i + 2) * N + (j + 1)\n            });\n        }\n    }\n}\n\ninline uint8_t get_state_override(const StateArray& st, int pos, int overridePos, uint8_t overrideState) {\n    return (pos == overridePos ? overrideState : st[pos]);\n}\n\ninline int ownerContrib(int pos, const StateArray& st, int overridePos = -1, uint8_t overrideState = 0) {\n    int i = pos / N, j = pos % N;\n    uint8_t s = get_state_override(st, pos, overridePos, overrideState);\n    uint8_t m = activeMask[s];\n    int g = 0;\n\n    if (j == 0 && (m & (1u << DIR_L))) g += BOUNDARY_PENALTY;\n    if (i == 0 && (m & (1u << DIR_U))) g += BOUNDARY_PENALTY;\n\n    if (j + 1 < N) {\n        bool a = (m >> DIR_R) & 1u;\n        bool b = (activeMask[get_state_override(st, pos + 1, overridePos, overrideState)] >> DIR_L) & 1u;\n        if (a && b) g += MATCH_REWARD;\n        else if (a != b) g += BROKEN_PENALTY;\n    } else {\n        if (m & (1u << DIR_R)) g += BOUNDARY_PENALTY;\n    }\n\n    if (i + 1 < N) {\n        bool a = (m >> DIR_D) & 1u;\n        bool b = (activeMask[get_state_override(st, pos + N, overridePos, overrideState)] >> DIR_U) & 1u;\n        if (a && b) g += MATCH_REWARD;\n        else if (a != b) g += BROKEN_PENALTY;\n    } else {\n        if (m & (1u << DIR_D)) g += BOUNDARY_PENALTY;\n    }\n\n    return g;\n}\n\ninline int localCellScore(int pos, uint8_t s, const StateArray& st) {\n    int sc = 0;\n    uint8_t mask = activeMask[s];\n    for (int d = 0; d < 4; d++) {\n        bool a = (mask >> d) & 1u;\n        int np = neighborPos[pos][d];\n        if (np == -1) {\n            if (a) sc += BOUNDARY_PENALTY;\n        } else {\n            bool b = (activeMask[st[np]] >> opp[d]) & 1u;\n            if (a && b) sc += MATCH_REWARD;\n            else if (a != b) sc += BROKEN_PENALTY;\n        }\n    }\n    return sc;\n}\n\nint calc_g(const StateArray& st) {\n    int g = 0;\n    for (int p = 0; p < P; p++) g += ownerContrib(p, st);\n    return g;\n}\n\nCycleEval evaluateCycles(const StateArray& st) {\n    CycleEval res;\n    static uint8_t vis[V];\n    static int stk[V];\n    memset(vis, 0, sizeof(vis));\n\n    int L1 = 0, L2 = 0, total = 0, numCycles = 0;\n\n    for (int p = 0; p < P; p++) {\n        uint8_t s = st[p];\n        uint8_t mask = activeMask[s];\n        int base = p << 2;\n\n        while (mask) {\n            int d = __builtin_ctz(mask);\n            mask &= mask - 1;\n            int v = base + d;\n            if (vis[v]) continue;\n\n            bool isCycle = true;\n            int vertices = 0;\n            int top = 0;\n            stk[top++] = v;\n            vis[v] = 1;\n\n            while (top) {\n                int u = stk[--top];\n                vertices++;\n\n                int pp = u >> 2;\n                int dd = u & 3;\n                uint8_t ss = st[pp];\n\n                int md = TO[ss][dd];\n                int u2 = (pp << 2) + md;\n                if (!vis[u2]) {\n                    vis[u2] = 1;\n                    stk[top++] = u2;\n                }\n\n                int np = neighborPos[pp][dd];\n                if (np != -1 && ((activeMask[st[np]] >> opp[dd]) & 1u)) {\n                    int u3 = (np << 2) + opp[dd];\n                    if (!vis[u3]) {\n                        vis[u3] = 1;\n                        stk[top++] = u3;\n                    }\n                } else {\n                    isCycle = false;\n                }\n            }\n\n            if (isCycle) {\n                int len = vertices / 2;\n                total += len;\n                numCycles++;\n                if (len > L1) {\n                    L2 = L1;\n                    L1 = len;\n                } else if (len > L2) {\n                    L2 = len;\n                }\n            }\n        }\n    }\n\n    res.L1 = L1;\n    res.L2 = L2;\n    res.total = total;\n    res.numCycles = numCycles;\n    res.score = (numCycles >= 2 ? 1LL * L1 * L2 : 0LL);\n    res.scalarNoG = res.score * SCORE_FACTOR\n                  + 1LL * res.L2 * L2_FACTOR\n                  + 1LL * res.L1 * L1_FACTOR\n                  + 2LL * res.total;\n    return res;\n}\n\nEval evaluateFull(const StateArray& st) {\n    int g = calc_g(st);\n    CycleEval c = evaluateCycles(st);\n    return make_eval(g, c);\n}\n\nvoid optimizeLocalG(StateArray& st, RNG& rng, int sweeps = 8) {\n    vector<int> order = nonDoublePos;\n    for (int sw = 0; sw < sweeps; sw++) {\n        shuffle_vec(order, rng);\n        bool changed = false;\n\n        for (int pos : order) {\n            uint8_t cur = st[pos];\n            int curScore = localCellScore(pos, cur, st);\n            int bestScore = curScore;\n            uint8_t bests[4];\n            int bc = 0;\n\n            for (int k = 0; k < allowedCnt[pos]; k++) {\n                uint8_t ns = allowedState[pos][k];\n                if (ns == cur) continue;\n                int sc = localCellScore(pos, ns, st);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bests[0] = ns;\n                    bc = 1;\n                } else if (sc == bestScore && sc > curScore) {\n                    bests[bc++] = ns;\n                }\n            }\n\n            if (bestScore > curScore) {\n                st[pos] = bests[rng.next_int(bc)];\n                changed = true;\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid optimizeG_SA(StateArray& st, RNG& rng, int steps) {\n    if (nonDoublePos.empty()) return;\n\n    int curG = calc_g(st);\n    int bestG = curG;\n    StateArray bestSt = st;\n\n    const double T0 = 4.0;\n    const double T1 = 0.03;\n\n    for (int step = 0; step < steps; step++) {\n        int pos = nonDoublePos[rng.next_int((int)nonDoublePos.size())];\n        uint8_t cur = st[pos];\n        uint8_t ns = allowedState[pos][rng.next_int(allowedCnt[pos])];\n        if (ns == cur) continue;\n\n        int before = ownerContrib(pos, st);\n        int lp = neighborPos[pos][DIR_L];\n        int up = neighborPos[pos][DIR_U];\n        if (lp != -1) before += ownerContrib(lp, st);\n        if (up != -1) before += ownerContrib(up, st);\n\n        int after = ownerContrib(pos, st, pos, ns);\n        if (lp != -1) after += ownerContrib(lp, st, pos, ns);\n        if (up != -1) after += ownerContrib(up, st, pos, ns);\n\n        int delta = after - before;\n\n        double a = (double)step / max(1, steps - 1);\n        double T = T0 * pow(T1 / T0, a);\n\n        if (delta >= 0 || rng.next_double() < exp((double)delta / T)) {\n            st[pos] = ns;\n            curG += delta;\n            if (curG > bestG) {\n                bestG = curG;\n                bestSt = st;\n            }\n        }\n    }\n\n    st = bestSt;\n}\n\nvoid addPool(vector<Candidate>& pool, const StateArray& st, int keep = 8) {\n    Candidate c;\n    c.st = st;\n    c.ev = evaluateFull(st);\n    pool.push_back(c);\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n    if ((int)pool.size() > keep) pool.resize(keep);\n}\n\nvoid applyDoublePattern(StateArray& st, int patId) {\n    for (int p : doublePos) {\n        int i = p / N, j = p % N;\n        uint8_t v = 4;\n        switch (patId) {\n            case 0: v = 4; break;\n            case 1: v = 5; break;\n            case 2: v = ((i + j) & 1) ? 4 : 5; break;\n            case 3: v = ((i + j) & 1) ? 5 : 4; break;\n            case 4: v = (i & 1) ? 4 : 5; break;\n            case 5: v = (i & 1) ? 5 : 4; break;\n            case 6: v = (j & 1) ? 4 : 5; break;\n            case 7: v = (j & 1) ? 5 : 4; break;\n            default: v = 4; break;\n        }\n        st[p] = v;\n    }\n}\n\nvoid applyDoubleRandomMode(StateArray& st, RNG& rng, int mode) {\n    if (mode == 0) {\n        for (int p : doublePos) st[p] = uint8_t(4 + rng.next_int(2));\n    } else if (mode == 1) {\n        uint8_t rowv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = rowv[p / N];\n    } else if (mode == 2) {\n        uint8_t colv[N];\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(4 + rng.next_int(2));\n        for (int p : doublePos) st[p] = colv[p % N];\n    } else {\n        uint8_t rowv[N], colv[N];\n        for (int i = 0; i < N; i++) rowv[i] = uint8_t(rng.next_int(2));\n        for (int j = 0; j < N; j++) colv[j] = uint8_t(rng.next_int(2));\n        int phase = rng.next_int(2);\n        for (int p : doublePos) {\n            int i = p / N, j = p % N;\n            st[p] = uint8_t(4 + ((rowv[i] ^ colv[j] ^ phase) & 1));\n        }\n    }\n}\n\nvoid hillDoubleSingle(StateArray& st, Eval& ev, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = doublePos;\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t ns = (orig == 4 ? 5 : 4);\n            st[pos] = ns;\n\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > ev.scalar) {\n                ev.c = c2;\n                ev.scalar = sc2;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid blockDouble2x2Pass(StateArray& st, Eval& ev, RNG& rng, int passes, double deadline) {\n    vector<int> order(blocks2x2.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int bi = 0; bi < (int)order.size(); bi++) {\n            if ((bi & 31) == 0 && elapsed_sec() > deadline) break;\n            const auto& b = blocks2x2[order[bi]];\n            int ps[4], k = 0;\n            for (int t = 0; t < 4; t++) {\n                if (isDoublePos[b[t]]) ps[k++] = b[t];\n            }\n            if (k <= 1) continue;\n\n            int origMask = 0;\n            for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n            int bestMask = origMask;\n            CycleEval bestC = ev.c;\n            long long bestScalar = ev.scalar;\n\n            int lim = 1 << k;\n            for (int mask = 0; mask < lim; mask++) {\n                if (mask == origMask) continue;\n                for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestScalar) {\n                    bestScalar = sc2;\n                    bestC = c2;\n                    bestMask = mask;\n                }\n            }\n\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n            if (bestMask != origMask) {\n                ev.c = bestC;\n                ev.scalar = bestScalar;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid scanDoubleWindows23Pass(StateArray& st, Eval& ev, RNG& rng, int passes, double deadline) {\n    vector<int> order(windows23.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int wi = 0; wi < (int)order.size(); wi++) {\n            if ((wi & 31) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& w = windows23[order[wi]];\n            int ps[6], k = 0;\n            for (int t = 0; t < 6; t++) if (isDoublePos[w[t]]) ps[k++] = w[t];\n            if (k < 4) continue;\n\n            int origMask = 0;\n            for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n            int bestMask = origMask;\n            CycleEval bestC = ev.c;\n            long long bestScalar = ev.scalar;\n\n            int lim = 1 << k;\n            for (int mask = 0; mask < lim; mask++) {\n                if (mask == origMask) continue;\n                for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestScalar) {\n                    bestScalar = sc2;\n                    bestC = c2;\n                    bestMask = mask;\n                }\n            }\n\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n            if (bestMask != origMask) {\n                ev.c = bestC;\n                ev.scalar = bestScalar;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid hillExactPositions(StateArray& st, Eval& ev, const vector<int>& positions, RNG& rng, int maxPass, double deadline) {\n    vector<int> order = positions;\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int idx = 0; idx < (int)order.size(); idx++) {\n            if ((idx & 31) == 0 && elapsed_sec() > deadline) break;\n\n            int pos = order[idx];\n            uint8_t orig = st[pos];\n            uint8_t bestState = orig;\n            Eval bestEv = ev;\n\n            if (isDoublePos[pos]) {\n                uint8_t ns = (orig == 4 ? 5 : 4);\n                st[pos] = ns;\n                CycleEval c2 = evaluateCycles(st);\n                long long sc2 = make_scalar(c2, ev.g);\n                if (sc2 > bestEv.scalar) {\n                    bestEv.c = c2;\n                    bestEv.scalar = sc2;\n                    bestState = ns;\n                }\n            } else {\n                for (int k = 0; k < allowedCnt[pos]; k++) {\n                    uint8_t ns = allowedState[pos][k];\n                    if (ns == orig) continue;\n                    st[pos] = ns;\n                    Eval e2 = evaluateFull(st);\n                    if (e2.scalar > bestEv.scalar) {\n                        bestEv = e2;\n                        bestState = ns;\n                    }\n                }\n            }\n\n            st[pos] = bestState;\n            if (bestState != orig) {\n                ev = bestEv;\n                improved = true;\n            } else {\n                st[pos] = orig;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid scanAll2x2Exact(StateArray& st, Eval& ev, RNG& rng, int passes, int prodLimit, double deadline) {\n    vector<int> order(blocks2x2.size());\n    iota(order.begin(), order.end(), 0);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (elapsed_sec() > deadline) break;\n        shuffle_vec(order, rng);\n        bool improved = false;\n\n        for (int bi = 0; bi < (int)order.size(); bi++) {\n            if ((bi & 15) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& b = blocks2x2[order[bi]];\n            int pos[4] = {b[0], b[1], b[2], b[3]};\n            int cnts[4];\n            uint8_t opts[4][4];\n            int prod = 1;\n            for (int t = 0; t < 4; t++) {\n                cnts[t] = allowedCnt[pos[t]];\n                prod *= cnts[t];\n                if (prod > prodLimit) break;\n                for (int k = 0; k < cnts[t]; k++) opts[t][k] = allowedState[pos[t]][k];\n            }\n            if (prod > prodLimit || prod <= 1) continue;\n\n            uint8_t bestStates[4];\n            for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n            Eval bestEv = ev;\n\n            for (int code = 0; code < prod; code++) {\n                int x = code;\n                for (int t = 0; t < 4; t++) {\n                    st[pos[t]] = opts[t][x % cnts[t]];\n                    x /= cnts[t];\n                }\n                Eval e2 = evaluateFull(st);\n                if (e2.scalar > bestEv.scalar) {\n                    bestEv = e2;\n                    for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n                }\n            }\n\n            for (int t = 0; t < 4; t++) st[pos[t]] = bestStates[t];\n            if (bestEv.scalar > ev.scalar) {\n                ev = bestEv;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid randomDoubleRegionSearch(StateArray& st, Eval& ev, RNG& rng, int iterations, double deadline) {\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int h = 2 + rng.next_int(2);\n        int w = 2 + rng.next_int(2);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        int ps[9];\n        int k = 0;\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) ps[k++] = p;\n            }\n        }\n        if (k <= 1 || k > 8) continue;\n\n        int origMask = 0;\n        for (int t = 0; t < k; t++) if (st[ps[t]] == 5) origMask |= (1 << t);\n\n        int bestMask = origMask;\n        CycleEval bestC = ev.c;\n        long long bestScalar = ev.scalar;\n\n        int lim = 1 << k;\n        for (int mask = 0; mask < lim; mask++) {\n            if (mask == origMask) continue;\n            for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((mask >> t & 1) ? 5 : 4);\n            CycleEval c2 = evaluateCycles(st);\n            long long sc2 = make_scalar(c2, ev.g);\n            if (sc2 > bestScalar) {\n                bestScalar = sc2;\n                bestC = c2;\n                bestMask = mask;\n            }\n        }\n\n        for (int t = 0; t < k; t++) st[ps[t]] = uint8_t((bestMask >> t & 1) ? 5 : 4);\n        if (bestMask != origMask) {\n            ev.c = bestC;\n            ev.scalar = bestScalar;\n        }\n    }\n}\n\nvector<int> buildNeighborhood(const vector<int>& touched) {\n    if (++curStampCell == INT_MAX) {\n        memset(seenStampCell, 0, sizeof(seenStampCell));\n        curStampCell = 1;\n    }\n    vector<int> res;\n    res.reserve(touched.size() * 5 + 8);\n\n    auto add = [&](int p) {\n        if (p < 0 || p >= P) return;\n        if (seenStampCell[p] == curStampCell) return;\n        seenStampCell[p] = curStampCell;\n        res.push_back(p);\n    };\n\n    for (int p : touched) {\n        add(p);\n        for (int d = 0; d < 4; d++) {\n            int np = neighborPos[p][d];\n            if (np != -1) add(np);\n        }\n    }\n    return res;\n}\n\nvector<int> buildBlocksAroundTouched(const vector<int>& touched) {\n    if (++curStampBlock == INT_MAX) {\n        memset(seenStampBlock, 0, sizeof(seenStampBlock));\n        curStampBlock = 1;\n    }\n    vector<int> res;\n    res.reserve(touched.size() * 4 + 8);\n\n    for (int p : touched) {\n        int i = p / N, j = p % N;\n        int i0 = max(0, i - 1), i1 = min(N - 2, i);\n        int j0 = max(0, j - 1), j1 = min(N - 2, j);\n        for (int bi = i0; bi <= i1; bi++) {\n            for (int bj = j0; bj <= j1; bj++) {\n                int id = bi * (N - 1) + bj;\n                if (seenStampBlock[id] == curStampBlock) continue;\n                seenStampBlock[id] = curStampBlock;\n                res.push_back(id);\n            }\n        }\n    }\n    return res;\n}\n\nvoid scan2x2BlockIdsExact(StateArray& st, Eval& ev, const vector<int>& ids, int prodLimit, RNG& rng, double deadline) {\n    vector<int> order = ids;\n    shuffle_vec(order, rng);\n    bool improved = true;\n\n    for (int pass = 0; pass < 2 && improved; pass++) {\n        improved = false;\n        for (int tbi = 0; tbi < (int)order.size(); tbi++) {\n            if ((tbi & 15) == 0 && elapsed_sec() > deadline) break;\n\n            const auto& b = blocks2x2[order[tbi]];\n            int pos[4] = {b[0], b[1], b[2], b[3]};\n            int cnts[4];\n            uint8_t opts[4][4];\n            int prod = 1;\n            for (int t = 0; t < 4; t++) {\n                cnts[t] = allowedCnt[pos[t]];\n                prod *= cnts[t];\n                if (prod > prodLimit) break;\n                for (int k = 0; k < cnts[t]; k++) opts[t][k] = allowedState[pos[t]][k];\n            }\n            if (prod > prodLimit || prod <= 1) continue;\n\n            uint8_t bestStates[4];\n            for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n            Eval bestEv = ev;\n\n            for (int code = 0; code < prod; code++) {\n                int x = code;\n                for (int t = 0; t < 4; t++) {\n                    st[pos[t]] = opts[t][x % cnts[t]];\n                    x /= cnts[t];\n                }\n                Eval e2 = evaluateFull(st);\n                if (e2.scalar > bestEv.scalar) {\n                    bestEv = e2;\n                    for (int t = 0; t < 4; t++) bestStates[t] = st[pos[t]];\n                }\n            }\n\n            for (int t = 0; t < 4; t++) st[pos[t]] = bestStates[t];\n            if (bestEv.scalar > ev.scalar) {\n                ev = bestEv;\n                improved = true;\n            }\n        }\n    }\n}\n\nvoid perturb(StateArray& st, RNG& rng, int strength, vector<int>& touched) {\n    touched.clear();\n    auto touch = [&](int p) { touched.push_back(p); };\n\n    int mode = rng.next_int(100);\n\n    if (mode < 55 && !doublePos.empty()) {\n        int h = 2 + rng.next_int(3);\n        int w = 2 + rng.next_int(3);\n        h = min(h, N);\n        w = min(w, N);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                int p = i * N + j;\n                if (isDoublePos[p]) {\n                    if (rng.next_int(100) < 80) {\n                        st[p] = (st[p] == 4 ? 5 : 4);\n                        touch(p);\n                    }\n                } else if (rng.next_int(100) < 20) {\n                    uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n                    if (ns != st[p]) {\n                        st[p] = ns;\n                        touch(p);\n                    }\n                }\n            }\n        }\n    } else {\n        int moves = 3 + rng.next_int(4) + min(8, strength / 4);\n        for (int t = 0; t < moves; t++) {\n            int p = rng.next_int(P);\n            uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n            if (ns != st[p]) {\n                st[p] = ns;\n                touch(p);\n            }\n        }\n    }\n\n    if (touched.empty()) {\n        int p = rng.next_int(P);\n        uint8_t ns = allowedState[p][rng.next_int(allowedCnt[p])];\n        if (ns != st[p]) st[p] = ns;\n        touch(p);\n    }\n}\n\n// ---------- crossover helpers ----------\n\nbool tryCopyDoublesFromDonor(StateArray& st, Eval& ev, const StateArray& donor,\n                             const vector<int>& posList, vector<int>* touched) {\n    vector<int> changed;\n    changed.reserve(posList.size());\n    for (int p : posList) {\n        if (!isDoublePos[p]) continue;\n        if (st[p] != donor[p]) {\n            changed.push_back(p);\n            st[p] = donor[p];\n        }\n    }\n    if (changed.empty()) return false;\n\n    CycleEval c2 = evaluateCycles(st);\n    long long sc2 = make_scalar(c2, ev.g);\n    if (sc2 > ev.scalar) {\n        ev.c = c2;\n        ev.scalar = sc2;\n        if (touched) {\n            for (int p : changed) touched->push_back(p);\n        }\n        return true;\n    }\n\n    for (int p : changed) st[p] = (donor[p] == 4 ? 5 : 4);\n    return false;\n}\n\nvoid greedyBandCrossoverDoubles(StateArray& st, Eval& ev, const StateArray& donor,\n                                RNG& rng, vector<int>& touched, double deadline) {\n    struct Band { int type, idx; };\n    vector<Band> bands;\n    bands.reserve(30 + 30 + 29 + 29);\n    for (int r = 0; r < N; r++) bands.push_back({0, r});\n    for (int c = 0; c < N; c++) bands.push_back({1, c});\n    for (int r = 0; r + 1 < N; r++) bands.push_back({2, r});\n    for (int c = 0; c + 1 < N; c++) bands.push_back({3, c});\n    shuffle_vec(bands, rng);\n\n    vector<int> pos;\n    pos.reserve(2 * N);\n\n    for (int bi = 0; bi < (int)bands.size(); bi++) {\n        if ((bi & 7) == 0 && elapsed_sec() > deadline) break;\n        pos.clear();\n\n        int type = bands[bi].type;\n        int idx = bands[bi].idx;\n        if (type == 0) {\n            int i = idx;\n            for (int j = 0; j < N; j++) pos.push_back(i * N + j);\n        } else if (type == 1) {\n            int j = idx;\n            for (int i = 0; i < N; i++) pos.push_back(i * N + j);\n        } else if (type == 2) {\n            int i = idx;\n            for (int j = 0; j < N; j++) {\n                pos.push_back(i * N + j);\n                pos.push_back((i + 1) * N + j);\n            }\n        } else {\n            int j = idx;\n            for (int i = 0; i < N; i++) {\n                pos.push_back(i * N + j);\n                pos.push_back(i * N + (j + 1));\n            }\n        }\n\n        tryCopyDoublesFromDonor(st, ev, donor, pos, &touched);\n    }\n}\n\nvoid randomRectCrossoverDoubles(StateArray& st, Eval& ev, const StateArray& donor,\n                                RNG& rng, int iters, vector<int>& touched, double deadline) {\n    vector<int> pos;\n    pos.reserve(P);\n\n    for (int it = 0; it < iters; it++) {\n        if ((it & 7) == 0 && elapsed_sec() > deadline) break;\n\n        int h = 2 + rng.next_int(7);\n        int w = 2 + rng.next_int(7);\n        if (rng.next_int(100) < 20) {\n            h = 2 + rng.next_int(11);\n            w = 2 + rng.next_int(11);\n        }\n        h = min(h, N);\n        w = min(w, N);\n        int si = rng.next_int(N - h + 1);\n        int sj = rng.next_int(N - w + 1);\n\n        pos.clear();\n        for (int i = si; i < si + h; i++) {\n            for (int j = sj; j < sj + w; j++) {\n                pos.push_back(i * N + j);\n            }\n        }\n        tryCopyDoublesFromDonor(st, ev, donor, pos, &touched);\n    }\n}\n\nbool tryAllPatchWithRepair(StateArray& st, Eval& ev, const StateArray& donor,\n                           const vector<int>& patch, RNG& rng, double deadline,\n                           vector<int>* touchedAccum) {\n    vector<int> changed;\n    changed.reserve(patch.size());\n    for (int p : patch) {\n        if (st[p] != donor[p]) {\n            changed.push_back(p);\n        }\n    }\n    if (changed.empty()) return false;\n\n    StateArray tmp = st;\n    for (int p : changed) tmp[p] = donor[p];\n    Eval tev = evaluateFull(tmp);\n\n    vector<int> neigh = buildNeighborhood(changed);\n    hillExactPositions(tmp, tev, neigh, rng, 1, deadline);\n    vector<int> blockIds = buildBlocksAroundTouched(changed);\n    scan2x2BlockIdsExact(tmp, tev, blockIds, 96, rng, deadline);\n\n    if (tev.scalar > ev.scalar) {\n        st = tmp;\n        ev = tev;\n        if (touchedAccum) {\n            for (int p : changed) touchedAccum->push_back(p);\n        }\n        return true;\n    }\n    return false;\n}\n\nvoid randomPatchCrossoverAll(StateArray& st, Eval& ev, const StateArray& donor,\n                             RNG& rng, int trials, vector<int>& touched, double deadline) {\n    vector<int> patch;\n    patch.reserve(P);\n\n    for (int it = 0; it < trials; it++) {\n        if (elapsed_sec() > deadline) break;\n        patch.clear();\n\n        int mode = rng.next_int(100);\n        if (mode < 35) {\n            int h = 1 + rng.next_int(3);\n            int si = rng.next_int(N - h + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = 0; j < N; j++) patch.push_back(i * N + j);\n            }\n        } else if (mode < 70) {\n            int w = 1 + rng.next_int(3);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = 0; i < N; i++) {\n                for (int j = sj; j < sj + w; j++) patch.push_back(i * N + j);\n            }\n        } else {\n            int h = 2 + rng.next_int(6);\n            int w = 2 + rng.next_int(6);\n            if (rng.next_int(100) < 25) {\n                h = 2 + rng.next_int(9);\n                w = 2 + rng.next_int(9);\n            }\n            h = min(h, N);\n            w = min(w, N);\n            int si = rng.next_int(N - h + 1);\n            int sj = rng.next_int(N - w + 1);\n            for (int i = si; i < si + h; i++) {\n                for (int j = sj; j < sj + w; j++) patch.push_back(i * N + j);\n            }\n        }\n\n        tryAllPatchWithRepair(st, ev, donor, patch, rng, deadline, &touched);\n    }\n}\n\nbool makeCrossoverChild(const Candidate& base, const Candidate& donor,\n                        StateArray& child, Eval& ev, RNG& rng,\n                        vector<int>& touched, double deadline) {\n    child = base.st;\n    ev = base.ev;\n    touched.clear();\n\n    greedyBandCrossoverDoubles(child, ev, donor.st, rng, touched, deadline);\n    randomRectCrossoverDoubles(child, ev, donor.st, rng, 12, touched, deadline);\n\n    if (rng.next_int(100) < 60) {\n        randomPatchCrossoverAll(child, ev, donor.st, rng, 2, touched, deadline);\n    }\n\n    return !touched.empty();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n    init_tables();\n\n    uint64_t seed = 1469598103934665603ULL;\n    vector<string> S(N);\n    for (int i = 0; i < N; i++) {\n        cin >> S[i];\n        for (char c : S[i]) {\n            seed ^= uint64_t((unsigned char)c + 1);\n            seed *= 1099511628211ULL;\n        }\n    }\n    RNG rng(seed);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int p = i * N + j;\n            int b = S[i][j] - '0';\n            baseTile[p] = (uint8_t)b;\n            isDoublePos[p] = (b == 4 || b == 5);\n            allPos.push_back(p);\n            if (isDoublePos[p]) doublePos.push_back(p);\n            else nonDoublePos.push_back(p);\n\n            int cnt = 0;\n            for (int s = 0; s < 8; s++) {\n                if (stateToRot[b][s] != 255) {\n                    allowedState[p][cnt++] = (uint8_t)s;\n                }\n            }\n            allowedCnt[p] = (uint8_t)cnt;\n        }\n    }\n\n    const double deadline = 1.95;\n\n    vector<Candidate> pool;\n    int baseStarts = 7;\n\n    for (int it = 0; it < baseStarts; it++) {\n        if (elapsed_sec() > 0.38) break;\n\n        StateArray base{};\n        for (int p = 0; p < P; p++) {\n            if (isDoublePos[p]) base[p] = 4;\n            else base[p] = allowedState[p][rng.next_int(allowedCnt[p])];\n        }\n\n        optimizeLocalG(base, rng, 6);\n        optimizeG_SA(base, rng, 18000);\n        optimizeLocalG(base, rng, 4);\n\n        for (int pat = 0; pat < 8; pat++) {\n            StateArray cand = base;\n            applyDoublePattern(cand, pat);\n            addPool(pool, cand, 8);\n        }\n        for (int mode = 0; mode < 4; mode++) {\n            StateArray cand = base;\n            applyDoubleRandomMode(cand, rng, mode);\n            addPool(pool, cand, 8);\n        }\n    }\n\n    if (pool.empty()) {\n        StateArray st{};\n        for (int p = 0; p < P; p++) st[p] = allowedState[p][0];\n        addPool(pool, st, 8);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    int refineCount = min<int>(3, pool.size());\n    for (int i = 0; i < refineCount; i++) {\n        if (elapsed_sec() > 1.00) break;\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n        blockDouble2x2Pass(pool[i].st, pool[i].ev, rng, 1, deadline);\n        if (i < 2) scanDoubleWindows23Pass(pool[i].st, pool[i].ev, rng, 1, deadline);\n        if (i < 2) hillExactPositions(pool[i].st, pool[i].ev, allPos, rng, 1, deadline);\n        if (i == 0 && elapsed_sec() < 1.38) {\n            scanAll2x2Exact(pool[i].st, pool[i].ev, rng, 1, 64, deadline);\n        }\n        hillDoubleSingle(pool[i].st, pool[i].ev, rng, 1, deadline);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    int topMix = min<int>(3, pool.size());\n    for (int a = 0; a < topMix; a++) {\n        for (int b = 0; b < topMix; b++) {\n            if (a == b) continue;\n            if (elapsed_sec() > 1.48) break;\n\n            StateArray child;\n            Eval ev;\n            vector<int> touched;\n            if (!makeCrossoverChild(pool[a], pool[b], child, ev, rng, touched, deadline)) continue;\n\n            vector<int> neigh = buildNeighborhood(touched);\n            hillExactPositions(child, ev, neigh, rng, 1, deadline);\n            vector<int> blockIds = buildBlocksAroundTouched(touched);\n            scan2x2BlockIdsExact(child, ev, blockIds, 128, rng, deadline);\n            hillDoubleSingle(child, ev, rng, 1, deadline);\n            if (rng.next_int(100) < 60) blockDouble2x2Pass(child, ev, rng, 1, deadline);\n\n            Candidate c;\n            c.st = child;\n            c.ev = ev;\n            pool.push_back(c);\n            sort(pool.begin(), pool.end(), [](const Candidate& x, const Candidate& y) {\n                return x.ev.scalar > y.ev.scalar;\n            });\n            if ((int)pool.size() > 8) pool.resize(8);\n        }\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.ev.scalar > b.ev.scalar;\n    });\n\n    Candidate best = pool[0];\n    Candidate current = best;\n    int stagnation = 0;\n\n    while (elapsed_sec() < deadline - 0.16) {\n        StateArray trial;\n        Eval tev;\n        vector<int> touched;\n\n        bool useCross = (stagnation >= 8 && (int)pool.size() >= 2 && rng.next_int(100) < 45);\n\n        if (useCross) {\n            int lim = min<int>(4, pool.size());\n            int ia = rng.next_int(lim);\n            int ib = rng.next_int(lim - 1);\n            if (ib >= ia) ib++;\n            if (!makeCrossoverChild(pool[ia], pool[ib], trial, tev, rng, touched, deadline)) {\n                trial = pool[ia].st;\n                tev = pool[ia].ev;\n                perturb(trial, rng, stagnation, touched);\n                tev = evaluateFull(trial);\n            }\n        } else {\n            trial = (rng.next_int(100) < 60 ? current.st : best.st);\n            perturb(trial, rng, stagnation, touched);\n            tev = evaluateFull(trial);\n        }\n\n        vector<int> neigh = buildNeighborhood(touched);\n        hillExactPositions(trial, tev, neigh, rng, 1, deadline);\n\n        vector<int> blockIds = buildBlocksAroundTouched(touched);\n        scan2x2BlockIdsExact(trial, tev, blockIds, 128, rng, deadline);\n\n        randomDoubleRegionSearch(trial, tev, rng, 12, deadline);\n        hillDoubleSingle(trial, tev, rng, 1, deadline);\n        if (rng.next_int(100) < 30) blockDouble2x2Pass(trial, tev, rng, 1, deadline);\n\n        if (tev.scalar > best.ev.scalar) {\n            best.st = trial;\n            best.ev = tev;\n            current = best;\n            stagnation = 0;\n            pool.push_back(best);\n            sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n                return a.ev.scalar > b.ev.scalar;\n            });\n            if ((int)pool.size() > 8) pool.resize(8);\n        } else {\n            stagnation++;\n        }\n\n        if (tev.scalar > current.ev.scalar || rng.next_int(100) < (stagnation < 10 ? 18 : 30)) {\n            current.st = trial;\n            current.ev = tev;\n        }\n\n        if (stagnation >= 20 && !pool.empty()) {\n            current = pool[rng.next_int((int)pool.size())];\n            stagnation = 0;\n        }\n    }\n\n    hillDoubleSingle(best.st, best.ev, rng, 2, deadline);\n    blockDouble2x2Pass(best.st, best.ev, rng, 2, deadline);\n    if (elapsed_sec() < deadline - 0.12) scanDoubleWindows23Pass(best.st, best.ev, rng, 1, deadline);\n    if (elapsed_sec() < deadline - 0.07) scanAll2x2Exact(best.st, best.ev, rng, 1, 64, deadline);\n    if (elapsed_sec() < deadline - 0.03) hillExactPositions(best.st, best.ev, allPos, rng, 1, deadline);\n    hillDoubleSingle(best.st, best.ev, rng, 1, deadline);\n\n    string ans;\n    ans.resize(P);\n    for (int p = 0; p < P; p++) {\n        uint8_t r = stateToRot[baseTile[p]][best.st[p]];\n        if (r == 255) r = 0;\n        ans[p] = char('0' + r);\n    }\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nstatic constexpr int MAXC = 100;\nstatic constexpr uint16_t NIL = 65535;\n\nstruct FastHash {\n    static ull splitmix64(ull 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()(ull x) const {\n        static const ull FIXED_RANDOM =\n            chrono::steady_clock::now().time_since_epoch().count();\n        return (size_t)splitmix64(x + FIXED_RANDOM);\n    }\n};\n\nstruct Metrics {\n    int tree = 1;\n    int largest_comp = 1;\n    int matched = 0;\n    int components = 1;\n    int cycle_excess = 0;\n    int full_tiles = 0;\n    int sumsq = 1;\n    int pot_max = 1;\n    int pot_sum = 1;\n    int hole_bad = 0;\n    int dist = 0;\n};\n\nstruct Node {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1; // 0:U 1:D 2:L 3:R\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct Cand {\n    array<unsigned char, MAXC> b{};\n    ull h = 0;\n    int blank = -1;\n    signed char last = -1;\n    uint16_t parent = NIL;\n    char mv = '?';\n    short tree = 1;\n    long long score = LLONG_MIN;\n};\n\nstruct SearchResult {\n    string best_tree_path;\n    int best_tree = 1;\n    string best_mode_path;\n    long long best_mode_score = LLONG_MIN;\n};\n\nstruct Solver {\n    int N, T, NN, FULL;\n    array<int, MAXC> nxtU, nxtD, nxtL, nxtR;\n    array<array<int, MAXC>, 4> nxtPos{};\n    array<int, MAXC> rr{}, cc{};\n    array<array<ull, 16>, MAXC> zob{};\n    ull lastSalt[5]{};\n    int popc[16]{};\n\n    chrono::steady_clock::time_point st;\n    double total_limit_sec = 2.82;\n\n    static ull splitmix64_ref(ull &x) {\n        ull z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    bool time_over(double deadline) const {\n        return elapsed() >= deadline;\n    }\n\n    static int hexval(char c) {\n        if ('0' <= c && c <= '9') return c - '0';\n        return c - 'a' + 10;\n    }\n\n    static int char_to_dir(char c) {\n        if (c == 'U') return 0;\n        if (c == 'D') return 1;\n        if (c == 'L') return 2;\n        return 3; // R\n    }\n\n    ull state_key(ull h, int last) const {\n        return h ^ lastSalt[last + 1];\n    }\n\n    string build_path(int depth, int idx,\n                      const vector<vector<uint16_t>> &parents,\n                      const vector<vector<char>> &moves) const {\n        string res(depth, '?');\n        while (depth > 0) {\n            res[depth - 1] = moves[depth][idx];\n            idx = parents[depth][idx];\n            --depth;\n        }\n        return res;\n    }\n\n    Metrics evaluate(const array<unsigned char, MAXC> &b, int blank) const {\n        int parent[MAXC];\n        int sz[MAXC];\n        int ed[MAXC];\n        unsigned char mdeg[MAXC];\n\n        for (int i = 0; i < NN; i++) {\n            mdeg[i] = 0;\n            if (b[i] == 0) {\n                parent[i] = -1;\n                sz[i] = 0;\n                ed[i] = 0;\n            } else {\n                parent[i] = i;\n                sz[i] = 1;\n                ed[i] = 0;\n            }\n        }\n\n        auto find = [&](int x) {\n            while (parent[x] != x) {\n                parent[x] = parent[parent[x]];\n                x = parent[x];\n            }\n            return x;\n        };\n\n        auto unite_edge = [&](int a, int c) {\n            int ra = find(a), rb = find(c);\n            if (ra == rb) {\n                ed[ra]++;\n            } else {\n                if (sz[ra] < sz[rb]) swap(ra, rb);\n                parent[rb] = ra;\n                sz[ra] += sz[rb];\n                ed[ra] += ed[rb] + 1;\n            }\n        };\n\n        Metrics m;\n        m.tree = 1;\n        m.largest_comp = 1;\n        m.matched = 0;\n        m.components = 0;\n        m.cycle_excess = 0;\n        m.full_tiles = 0;\n        m.sumsq = 0;\n        m.pot_max = 1;\n        m.pot_sum = 0;\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n\n            int r = nxtR[i];\n            if (r != -1) {\n                unsigned char tr = b[r];\n                if ((t & 4) && (tr & 1)) {\n                    unite_edge(i, r);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[r]++;\n                }\n            }\n\n            int d = nxtD[i];\n            if (d != -1) {\n                unsigned char td = b[d];\n                if ((t & 8) && (td & 2)) {\n                    unite_edge(i, d);\n                    m.matched++;\n                    mdeg[i]++;\n                    mdeg[d]++;\n                }\n            }\n        }\n\n        for (int i = 0; i < NN; i++) {\n            unsigned char t = b[i];\n            if (t == 0) continue;\n            if ((int)mdeg[i] == popc[t]) m.full_tiles++;\n        }\n\n        for (int i = 0; i < NN; i++) {\n            if (parent[i] == i) {\n                m.components++;\n                int v = sz[i];\n                int ex = ed[i] - v + 1;\n                if (ex < 0) ex = 0;\n                m.cycle_excess += ex;\n                m.largest_comp = max(m.largest_comp, v);\n                if (ed[i] == v - 1) m.tree = max(m.tree, v);\n                m.sumsq += v * v;\n                int pot = v - 2 * ex;\n                if (pot < 0) pot = 0;\n                m.pot_max = max(m.pot_max, pot);\n                m.pot_sum += pot;\n            }\n        }\n\n        // hole conflicts: stubs pointing into the blank\n        m.hole_bad = 0;\n        int u = nxtU[blank], d = nxtD[blank], l = nxtL[blank], r = nxtR[blank];\n        if (u != -1 && (b[u] & 8)) m.hole_bad++;\n        if (d != -1 && (b[d] & 2)) m.hole_bad++;\n        if (l != -1 && (b[l] & 4)) m.hole_bad++;\n        if (r != -1 && (b[r] & 1)) m.hole_bad++;\n\n        m.dist = (N - 1 - rr[blank]) + (N - 1 - cc[blank]);\n\n        return m;\n    }\n\n    long long score_of(const Metrics &m, int mode) const {\n        if (mode == 0) {\n            // Global completion-oriented:\n            // fewer cycles/components via matched-3*cycles,\n            // more fully satisfied tiles, bigger merged regions.\n            return\n                1'000'000'000'000LL * (m.matched - 3 * m.cycle_excess) +\n                1'000'000'000LL * m.full_tiles +\n                100'000LL * m.sumsq +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        } else if (mode == 1) {\n            // Large near-tree component.\n            return\n                1'000'000'000'000LL * m.pot_max +\n                1'000'000'000LL * m.tree +\n                1'000'000LL * (m.matched - 2 * m.cycle_excess) +\n                1'000LL * m.full_tiles +\n                m.largest_comp -\n                10LL * m.hole_bad;\n        } else {\n            // Local consistency.\n            return\n                1'000'000'000'000LL * m.full_tiles +\n                1'000'000'000LL * m.matched +\n                1'000'000LL * m.pot_sum +\n                1'000LL * m.largest_comp +\n                m.tree -\n                10LL * m.hole_bad -\n                m.dist;\n        }\n    }\n\n    SearchResult beam_search(const array<unsigned char, MAXC> &start_board,\n                             int start_blank,\n                             int depth_limit,\n                             int mode,\n                             int width,\n                             double deadline,\n                             int start_last = -1,\n                             ull tie_salt = 0) {\n        SearchResult res;\n\n        Node root;\n        root.b = start_board;\n        root.blank = start_blank;\n        root.last = (signed char)start_last;\n        root.h = 0;\n        for (int i = 0; i < NN; i++) root.h ^= zob[i][root.b[i]];\n\n        Metrics rm = evaluate(root.b, root.blank);\n        root.tree = (short)rm.tree;\n        root.score = score_of(rm, mode);\n\n        res.best_tree = root.tree;\n        res.best_tree_path = \"\";\n        res.best_mode_score = root.score;\n        res.best_mode_path = \"\";\n\n        if (root.tree == FULL || depth_limit == 0) return res;\n\n        vector<Node> cur, next;\n        cur.reserve(width);\n        next.reserve(width);\n        cur.push_back(root);\n\n        vector<vector<uint16_t>> parents(depth_limit + 1);\n        vector<vector<char>> moves(depth_limit + 1);\n        parents[0].push_back(NIL);\n        moves[0].push_back('?');\n\n        unordered_set<ull, FastHash> seen;\n        {\n            size_t est = (size_t)min<long long>((long long)width * min(depth_limit, 1500) + 1024LL, 2'000'000LL);\n            seen.reserve(est * 2 + 1);\n            seen.max_load_factor(0.7f);\n        }\n        seen.insert(state_key(root.h, root.last));\n\n        const int inv[4] = {1, 0, 3, 2};\n        const char dirc[4] = {'U', 'D', 'L', 'R'};\n\n        vector<Cand> cands;\n        cands.reserve(width * 3 + 8);\n\n        int blankCap = (N <= 7 ? 12 : 8);\n        int blankLastCap = 3;\n\n        for (int depth = 0; depth < depth_limit; depth++) {\n            if (time_over(deadline)) break;\n\n            cands.clear();\n\n            for (int pi = 0; pi < (int)cur.size(); pi++) {\n                if ((pi & 31) == 0 && time_over(deadline)) break;\n                const Node &nd = cur[pi];\n\n                for (int dir = 0; dir < 4; dir++) {\n                    if (nd.last != -1 && inv[dir] == nd.last) continue;\n                    int nb = nxtPos[dir][nd.blank];\n                    if (nb == -1) continue;\n\n                    unsigned char tile = nd.b[nb];\n                    ull nh = nd.h ^ zob[nd.blank][0] ^ zob[nb][tile] ^ zob[nd.blank][tile] ^ zob[nb][0];\n                    ull key = state_key(nh, dir);\n                    if (seen.find(key) != seen.end()) continue;\n\n                    Cand cd;\n                    cd.b = nd.b;\n                    cd.b[nd.blank] = tile;\n                    cd.b[nb] = 0;\n                    cd.h = nh;\n                    cd.blank = nb;\n                    cd.last = (signed char)dir;\n                    cd.parent = (uint16_t)pi;\n                    cd.mv = dirc[dir];\n\n                    Metrics m = evaluate(cd.b, cd.blank);\n                    cd.tree = (short)m.tree;\n                    cd.score = score_of(m, mode);\n\n                    cands.push_back(std::move(cd));\n\n                    if (m.tree > res.best_tree) {\n                        res.best_tree = m.tree;\n                        res.best_tree_path = build_path(depth, pi, parents, moves);\n                        res.best_tree_path.push_back(dirc[dir]);\n                        if (m.tree == FULL) return res;\n                    }\n                }\n            }\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const Cand &a, const Cand &b) {\n                if (a.score != b.score) return a.score > b.score;\n                return (a.h ^ tie_salt) < (b.h ^ tie_salt);\n            });\n\n            unordered_set<ull, FastHash> used;\n            used.reserve(cands.size() * 2 + 1);\n            used.max_load_factor(0.7f);\n\n            vector<unsigned char> blankCnt(NN, 0);\n            vector<array<unsigned char, 4>> blankLastCnt(NN);\n            for (int i = 0; i < NN; i++) blankLastCnt[i] = {0, 0, 0, 0};\n\n            next.clear();\n            parents[depth + 1].clear();\n            moves[depth + 1].clear();\n            next.reserve(width);\n            parents[depth + 1].reserve(width);\n            moves[depth + 1].reserve(width);\n\n            auto try_add = [&](const Cand &cd, bool use_cap) -> bool {\n                ull key = state_key(cd.h, cd.last);\n                if (used.find(key) != used.end()) return false;\n                if (seen.find(key) != seen.end()) return false;\n\n                if (use_cap) {\n                    if (blankCnt[cd.blank] >= blankCap) return false;\n                    if (blankLastCnt[cd.blank][cd.last] >= blankLastCap) return false;\n                }\n\n                used.insert(key);\n                seen.insert(key);\n                blankCnt[cd.blank]++;\n                blankLastCnt[cd.blank][cd.last]++;\n\n                Node nd;\n                nd.b = cd.b;\n                nd.h = cd.h;\n                nd.blank = cd.blank;\n                nd.last = cd.last;\n                nd.tree = cd.tree;\n                nd.score = cd.score;\n                next.push_back(std::move(nd));\n                parents[depth + 1].push_back(cd.parent);\n                moves[depth + 1].push_back(cd.mv);\n\n                if (cd.score > res.best_mode_score) {\n                    res.best_mode_score = cd.score;\n                    res.best_mode_path = build_path(depth + 1, (int)next.size() - 1, parents, moves);\n                }\n                return true;\n            };\n\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, true);\n            }\n            for (const auto &cd : cands) {\n                if ((int)next.size() >= width) break;\n                try_add(cd, false);\n            }\n\n            if (next.empty()) break;\n            cur.swap(next);\n        }\n\n        return res;\n    }\n\n    void apply_moves(array<unsigned char, MAXC> &b, int &blank, const string &path) const {\n        for (char c : path) {\n            int dir = char_to_dir(c);\n            int nb = nxtPos[dir][blank];\n            unsigned char tile = b[nb];\n            b[blank] = tile;\n            b[nb] = 0;\n            blank = nb;\n        }\n    }\n\n    bool better_solution(int treeA, int lenA, int treeB, int lenB) const {\n        if (treeA != treeB) return treeA > treeB;\n        if (treeA == FULL && treeB == FULL) return lenA < lenB;\n        return false;\n    }\n\n    int base_width() const {\n        if (N <= 6) return 2200;\n        if (N == 7) return 1600;\n        if (N == 8) return 950;\n        if (N == 9) return 650;\n        return 450;\n    }\n\n    void solve() {\n        cin >> N >> T;\n        NN = N * N;\n        FULL = NN - 1;\n\n        array<unsigned char, MAXC> init_board{};\n        int init_blank = -1;\n        for (int i = 0; i < N; i++) {\n            string s;\n            cin >> s;\n            for (int j = 0; j < N; j++) {\n                int v = hexval(s[j]);\n                init_board[i * N + j] = (unsigned char)v;\n                if (v == 0) init_blank = i * N + j;\n            }\n        }\n\n        for (int i = 0; i < 16; i++) popc[i] = __builtin_popcount(i);\n\n        for (int i = 0; i < NN; i++) {\n            int r = i / N, c = i % N;\n            rr[i] = r;\n            cc[i] = c;\n            nxtU[i] = (r > 0 ? i - N : -1);\n            nxtD[i] = (r + 1 < N ? i + N : -1);\n            nxtL[i] = (c > 0 ? i - 1 : -1);\n            nxtR[i] = (c + 1 < N ? i + 1 : -1);\n            nxtPos[0][i] = nxtU[i];\n            nxtPos[1][i] = nxtD[i];\n            nxtPos[2][i] = nxtL[i];\n            nxtPos[3][i] = nxtR[i];\n        }\n\n        ull seed = 0x123456789abcdef0ULL;\n        for (int i = 0; i < NN; i++) {\n            for (int v = 0; v < 16; v++) zob[i][v] = splitmix64_ref(seed);\n        }\n        for (int i = 0; i < 5; i++) lastSalt[i] = splitmix64_ref(seed);\n\n        st = chrono::steady_clock::now();\n\n        Metrics initM = evaluate(init_board, init_blank);\n        string best_path = \"\";\n        int best_tree = initM.tree;\n\n        int W = base_width();\n\n        double d1 = total_limit_sec * 0.40;\n        double d2 = total_limit_sec * 0.72;\n        double d3 = total_limit_sec * 0.90;\n        double d4 = total_limit_sec - 0.02;\n\n        ull salt1 = splitmix64_ref(seed);\n        ull salt2 = splitmix64_ref(seed);\n        ull salt3 = splitmix64_ref(seed);\n        ull salt4 = splitmix64_ref(seed);\n\n        SearchResult r0, r1;\n\n        // Run 1: global-completion beam\n        if (!time_over(d1)) {\n            r0 = beam_search(init_board, init_blank, T, 0, W, d1, -1, salt1);\n            if (better_solution(r0.best_tree, (int)r0.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r0.best_tree;\n                best_path = r0.best_tree_path;\n            }\n        }\n\n        // Run 2: big-near-tree beam\n        if (!time_over(d2)) {\n            r1 = beam_search(init_board, init_blank, T, 1, (W * 3) / 4, d2, -1, salt2);\n            if (better_solution(r1.best_tree, (int)r1.best_tree_path.size(), best_tree, (int)best_path.size())) {\n                best_tree = r1.best_tree;\n                best_path = r1.best_tree_path;\n            }\n        }\n\n        // Choose a promising intermediate path for refinement.\n        vector<string> candidates;\n        candidates.push_back(best_path);\n        candidates.push_back(r0.best_mode_path);\n        candidates.push_back(r1.best_mode_path);\n        candidates.push_back(r0.best_tree_path);\n        candidates.push_back(r1.best_tree_path);\n\n        sort(candidates.begin(), candidates.end());\n        candidates.erase(unique(candidates.begin(), candidates.end()), candidates.end());\n\n        string refine_start = best_path;\n        long long refine_best_score = LLONG_MIN;\n        int refine_best_len = (int)best_path.size();\n\n        for (const string &p : candidates) {\n            if ((int)p.size() > T) continue;\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, p);\n            Metrics m = evaluate(b, blank);\n            long long sc = score_of(m, 0); // completion-oriented\n            if (sc > refine_best_score || (sc == refine_best_score && (int)p.size() < refine_best_len)) {\n                refine_best_score = sc;\n                refine_best_len = (int)p.size();\n                refine_start = p;\n            }\n        }\n\n        // Refinement 1 from the most completion-promising state.\n        if (!time_over(d3) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, refine_start);\n            int rem = T - (int)refine_start.size();\n            int stlast = refine_start.empty() ? -1 : char_to_dir(refine_start.back());\n            if (rem > 0) {\n                auto rr0 = beam_search(b, blank, rem, 0, (W * 2) / 3, d3, stlast, salt3);\n                string cand_path = refine_start + rr0.best_tree_path;\n                if (better_solution(rr0.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr0.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        // Refinement 2 from current best tree state, slightly different heuristic.\n        if (!time_over(d4) && best_tree < FULL) {\n            array<unsigned char, MAXC> b = init_board;\n            int blank = init_blank;\n            apply_moves(b, blank, best_path);\n            int rem = T - (int)best_path.size();\n            int stlast = best_path.empty() ? -1 : char_to_dir(best_path.back());\n            if (rem > 0) {\n                auto rr1 = beam_search(b, blank, rem, 1, max(120, W / 2), d4, stlast, salt4);\n                string cand_path = best_path + rr1.best_tree_path;\n                if (better_solution(rr1.best_tree, (int)cand_path.size(), best_tree, (int)best_path.size())) {\n                    best_tree = rr1.best_tree;\n                    best_path = cand_path;\n                }\n            }\n        }\n\n        cout << best_path << '\\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}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstatic constexpr int R = 10000;\nstatic constexpr int MAX_CUTS = 100;\nstatic constexpr int NORMAL_MAX = 4096;\nstatic constexpr int MIN_NORM = 1000;\nstatic constexpr long double SQRT3 = 1.7320508075688772935L;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Line {\n    int A, B; // primitive, sign-normalized\n    ll C;     // A x + B y = C\n};\n\nstruct State {\n    vector<int> cell;\n    vector<int> cellSize;\n    array<int, 11> hist{};\n    int rawScore = 0;\n    int overflow = 0;   // sum max(0, hist[d] - a_d)\n    int smallCount = 0; // #cells with size 1..10\n    int mass10 = 0;     // sum min(cell_size, 10)\n};\n\nstruct Cand2 {\n    int A, B;\n    int t1, t2;\n    double alpha1, alpha2;\n    double off1, off2;\n};\n\nstruct Cand3 {\n    array<pair<int,int>,3> n;\n    int t[3];\n    double alpha[3];\n    double off[3];\n};\n\nstruct BestLineRes {\n    bool ok = false;\n    int raw = -1000000000;\n    int overflow = 1000000000;\n    int mass10 = -1000000000;\n    int small = -1000000000;\n    Line line{};\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = 88172645463393265ull) : x(seed ? seed : 88172645463393265ull) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double uniform() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    double uniform(double l, double r) {\n        return l + (r - l) * uniform();\n    }\n    ll next_ll(ll l, ll r) {\n        if (l > r) swap(l, r);\n        unsigned long long w = (unsigned long long)(r - l + 1);\n        return l + (ll)(next() % w);\n    }\n    int next_int(int l, int r) {\n        return (int)next_ll(l, r);\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\nint N, K;\nint a_need[11];\nint attendees_sum = 0;\nvector<Pt> pts;\nXorShift64 rng(1);\n\ntemplate <class T>\nT clampv(T x, T l, T r) {\n    return min(r, max(l, x));\n}\n\nstatic inline ll proj(int A, int B, const Pt& p) {\n    return 1LL * A * p.x + 1LL * B * p.y;\n}\n\nstatic inline ll norm2(pair<int,int> p) {\n    return 1LL * p.first * p.first + 1LL * p.second * p.second;\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\npair<int,int> normalize_pair(ll A, ll B) {\n    if (A == 0 && B == 0) return {0, 0};\n    ll g = std::gcd(std::llabs(A), std::llabs(B));\n    A /= g;\n    B /= g;\n    if (A < 0 || (A == 0 && B < 0)) {\n        A = -A;\n        B = -B;\n    }\n    return {(int)A, (int)B};\n}\n\npair<int,int> random_primitive_large() {\n    while (true) {\n        ll A = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        ll B = rng.next_ll(-NORMAL_MAX, NORMAL_MAX);\n        if (A == 0 && B == 0) continue;\n        auto p = normalize_pair(A, B);\n        if (norm2(p) < 1LL * MIN_NORM * MIN_NORM) continue;\n        return p;\n    }\n}\n\npair<int,int> rotate60(pair<int,int> p) {\n    long double x = 0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first + 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\npair<int,int> rotate120(pair<int,int> p) {\n    long double x = -0.5L * p.first - (SQRT3 * 0.5L) * p.second;\n    long double y = (SQRT3 * 0.5L) * p.first - 0.5L * p.second;\n    return normalize_pair(llround(x), llround(y));\n}\n\nbool better_metrics(int raw1, int ov1, int mass1, int small1,\n                    int raw2, int ov2, int mass2, int small2) {\n    if (raw1 != raw2) return raw1 > raw2;\n    if (ov1 != ov2) return ov1 < ov2;\n    if (mass1 != mass2) return mass1 > mass2;\n    return small1 > small2;\n}\n\nbool same_metrics(int raw1, int ov1, int mass1, int small1,\n                  int raw2, int ov2, int mass2, int small2) {\n    return raw1 == raw2 && ov1 == ov2 && mass1 == mass2 && small1 == small2;\n}\n\nint compute_raw_from_hist(const array<int,11>& hist) {\n    int raw = 0;\n    for (int d = 1; d <= 10; d++) raw += min(a_need[d], hist[d]);\n    return raw;\n}\n\nint compute_overflow_from_hist(const array<int,11>& hist) {\n    int ov = 0;\n    for (int d = 1; d <= 10; d++) ov += max(0, hist[d] - a_need[d]);\n    return ov;\n}\n\nvoid recompute_score(State& st) {\n    st.hist.fill(0);\n    st.smallCount = 0;\n    st.mass10 = 0;\n    for (int s : st.cellSize) {\n        if (1 <= s && s <= 10) {\n            st.hist[s]++;\n            st.smallCount++;\n        }\n        st.mass10 += min(s, 10);\n    }\n    st.rawScore = compute_raw_from_hist(st.hist);\n    st.overflow = compute_overflow_from_hist(st.hist);\n}\n\nint index_from_proj(ll u, ll start, ll step, int t) {\n    ll d = u - start;\n    if (d < 0) return 0;\n    ll q = d / step;\n    if (q >= t) return t;\n    if (d % step == 0) return -1;\n    return (int)q + 1;\n}\n\nint raw_from_counts(const vector<int>& cnt) {\n    array<int,11> hist{};\n    for (int c : cnt) if (1 <= c && c <= 10) hist[c]++;\n    return compute_raw_from_hist(hist);\n}\n\nint eval_cand2(const Cand2& c) {\n    static vector<int> cnt;\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    int A1 = c.A, B1 = c.B;\n    auto n2 = normalize_pair(-c.B, c.A);\n    int A2 = n2.first, B2 = n2.second;\n\n    int W = c.t2 + 1;\n    int SZ = (c.t1 + 1) * (c.t2 + 1);\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int i = index_from_proj(proj(A1, B1, p), start1, step1, c.t1);\n        if (i < 0) continue;\n        int j = index_from_proj(proj(A2, B2, p), start2, step2, c.t2);\n        if (j < 0) continue;\n        cnt[i * W + j]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nint eval_cand3(const Cand3& c) {\n    static vector<int> cnt;\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    int W1 = c.t[1] + 1;\n    int W2 = c.t[2] + 1;\n    int SZ = (c.t[0] + 1) * W1 * W2;\n    cnt.assign(SZ, 0);\n\n    for (const auto& p : pts) {\n        int idx[3];\n        bool bad = false;\n        for (int k = 0; k < 3; k++) {\n            idx[k] = index_from_proj(proj(c.n[k].first, c.n[k].second, p), start[k], step[k], c.t[k]);\n            if (idx[k] < 0) {\n                bad = true;\n                break;\n            }\n        }\n        if (bad) continue;\n        int id = (idx[0] * W1 + idx[1]) * W2 + idx[2];\n        cnt[id]++;\n    }\n    return raw_from_counts(cnt);\n}\n\nbool has_collision_line(int A, int B, ll C) {\n    for (const auto& p : pts) if (proj(A, B, p) == C) return true;\n    return false;\n}\n\nll find_valid_C_near(int A, int B, ll base, unordered_set<ll>& used) {\n    auto bad = [&](ll C)->bool {\n        if (used.find(C) != used.end()) return true;\n        return has_collision_line(A, B, C);\n    };\n    if (!bad(base)) return base;\n    for (ll d = 1;; d++) {\n        if (!bad(base + d)) return base + d;\n        if (!bad(base - d)) return base - d;\n    }\n}\n\nvector<Line> build_lines2(const Cand2& c) {\n    auto n1 = normalize_pair(c.A, c.B);\n    auto n2 = normalize_pair(-c.B, c.A);\n\n    long double g = sqrt((long double)c.A * c.A + (long double)c.B * c.B);\n    ll step1 = max<ll>(1, llround(2.0L * R * c.alpha1 * g / (c.t1 + 1)));\n    ll step2 = max<ll>(1, llround(2.0L * R * c.alpha2 * g / (c.t2 + 1)));\n    ll start1 = llround(((-0.5L * (c.t1 - 1)) + c.off1) * step1);\n    ll start2 = llround(((-0.5L * (c.t2 - 1)) + c.off2) * step2);\n\n    vector<Line> res;\n    res.reserve(c.t1 + c.t2);\n\n    unordered_set<ll> used1, used2;\n    used1.reserve(c.t1 * 2 + 3);\n    used2.reserve(c.t2 * 2 + 3);\n\n    for (int j = 0; j < c.t1; j++) {\n        ll C = start1 + 1LL * j * step1;\n        C = find_valid_C_near(n1.first, n1.second, C, used1);\n        used1.insert(C);\n        res.push_back(Line{n1.first, n1.second, C});\n    }\n    for (int j = 0; j < c.t2; j++) {\n        ll C = start2 + 1LL * j * step2;\n        C = find_valid_C_near(n2.first, n2.second, C, used2);\n        used2.insert(C);\n        res.push_back(Line{n2.first, n2.second, C});\n    }\n    return res;\n}\n\nvector<Line> build_lines3(const Cand3& c) {\n    ll step[3], start[3];\n    for (int k = 0; k < 3; k++) {\n        long double g = sqrt((long double)c.n[k].first * c.n[k].first + (long double)c.n[k].second * c.n[k].second);\n        step[k] = max<ll>(1, llround(2.0L * R * c.alpha[k] * g / (c.t[k] + 1)));\n        start[k] = llround(((-0.5L * (c.t[k] - 1)) + c.off[k]) * step[k]);\n    }\n\n    vector<Line> res;\n    res.reserve(c.t[0] + c.t[1] + c.t[2]);\n\n    unordered_set<ll> used[3];\n    for (int k = 0; k < 3; k++) used[k].reserve(c.t[k] * 2 + 3);\n\n    for (int k = 0; k < 3; k++) {\n        auto n = normalize_pair(c.n[k].first, c.n[k].second);\n        for (int j = 0; j < c.t[k]; j++) {\n            ll C = start[k] + 1LL * j * step[k];\n            C = find_valid_C_near(n.first, n.second, C, used[k]);\n            used[k].insert(C);\n            res.push_back(Line{n.first, n.second, C});\n        }\n    }\n    return res;\n}\n\nvoid apply_line(State& st, const Line& ln) {\n    int M = (int)st.cellSize.size();\n\n    static vector<int> pos, neg, newPosId, newNegId;\n    static vector<unsigned char> side;\n\n    pos.assign(M, 0);\n    neg.assign(M, 0);\n    side.assign(N, 0);\n\n    for (int i = 0; i < N; i++) {\n        ll v = proj(ln.A, ln.B, pts[i]) - ln.C;\n        int id = st.cell[i];\n        if (v > 0) {\n            side[i] = 1;\n            pos[id]++;\n        } else {\n            side[i] = 0;\n            neg[id]++;\n        }\n    }\n\n    newPosId.assign(M, -1);\n    newNegId.assign(M, -1);\n    vector<int> newSizes;\n    newSizes.reserve(min(N, 2 * M));\n\n    for (int id = 0; id < M; id++) {\n        if (neg[id] > 0) {\n            newNegId[id] = (int)newSizes.size();\n            newSizes.push_back(neg[id]);\n        }\n        if (pos[id] > 0) {\n            newPosId[id] = (int)newSizes.size();\n            newSizes.push_back(pos[id]);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        int old = st.cell[i];\n        st.cell[i] = side[i] ? newPosId[old] : newNegId[old];\n    }\n    st.cellSize.swap(newSizes);\n    recompute_score(st);\n}\n\nState build_state_excluding(const vector<Line>& lines, int skip = -1) {\n    State st;\n    st.cell.assign(N, 0);\n    st.cellSize = {N};\n    recompute_score(st);\n    for (int i = 0; i < (int)lines.size(); i++) {\n        if (i == skip) continue;\n        apply_line(st, lines[i]);\n    }\n    return st;\n}\n\nState build_state(const vector<Line>& lines) {\n    return build_state_excluding(lines, -1);\n}\n\ndouble estimate_lambda_star() {\n    double bestLam = max(1.0, (double)N / attendees_sum);\n    double bestVal = -1e100;\n    for (double lam = 0.8; lam <= 10.0; lam += 0.02) {\n        double C = N / lam;\n        double p = exp(-lam);\n        double cur = 0.0;\n        double pk = p;\n        for (int d = 1; d <= 10; d++) {\n            pk *= lam / d;\n            cur += min<double>(a_need[d], C * pk);\n        }\n        if (cur > bestVal) {\n            bestVal = cur;\n            bestLam = lam;\n        }\n    }\n    return bestLam;\n}\n\nCand2 random_cand2(double lambdaCenter) {\n    Cand2 c;\n    auto n = random_primitive_large();\n    c.A = n.first;\n    c.B = n.second;\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.85, 0.85)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double aspect = exp(rng.uniform(-0.8, 0.8));\n    double prod = 4.0 * Ctarget / acos(-1.0);\n\n    c.t1 = max(1, (int)llround(sqrt(prod * aspect) - 1.0));\n    c.t2 = max(1, (int)llround(sqrt(prod / aspect) - 1.0));\n\n    int sum = c.t1 + c.t2;\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        c.t1 = max(1, (int)floor(c.t1 * sc));\n        c.t2 = max(1, (int)floor(c.t2 * sc));\n        while (c.t1 + c.t2 > MAX_CUTS) {\n            if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n            else if (c.t2 > 1) c.t2--;\n            else break;\n        }\n    }\n\n    c.alpha1 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.alpha2 = clampv(exp(rng.uniform(-0.5, 0.5)), 0.45, 1.8);\n    c.off1 = rng.uniform(-0.5, 0.5);\n    c.off2 = rng.uniform(-0.5, 0.5);\n    return c;\n}\n\nCand3 random_cand3(double lambdaCenter) {\n    Cand3 c;\n    while (true) {\n        auto n0 = random_primitive_large();\n        auto n1 = rotate60(n0);\n        auto n2 = rotate120(n0);\n        if ((n1.first || n1.second) && (n2.first || n2.second)\n            && norm2(n1) >= 250000 && norm2(n2) >= 250000) {\n            c.n[0] = n0;\n            c.n[1] = n1;\n            c.n[2] = n2;\n            break;\n        }\n    }\n\n    double lambda = clampv(lambdaCenter * exp(rng.uniform(-0.8, 0.8)), 1.0, 12.0);\n    double Ctarget = N / lambda;\n    double base = sqrt(max(1.0, Ctarget / 3.0));\n\n    for (int k = 0; k < 3; k++) {\n        c.t[k] = max(1, (int)llround(base * exp(rng.uniform(-0.45, 0.45))));\n    }\n\n    int sum = c.t[0] + c.t[1] + c.t[2];\n    if (sum > MAX_CUTS) {\n        double sc = (double)MAX_CUTS / sum;\n        for (int k = 0; k < 3; k++) c.t[k] = max(1, (int)floor(c.t[k] * sc));\n        while (c.t[0] + c.t[1] + c.t[2] > MAX_CUTS) {\n            int id = 0;\n            if (c.t[1] > c.t[id]) id = 1;\n            if (c.t[2] > c.t[id]) id = 2;\n            if (c.t[id] > 1) c.t[id]--;\n            else break;\n        }\n    }\n\n    for (int k = 0; k < 3; k++) {\n        c.alpha[k] = clampv(exp(rng.uniform(-0.35, 0.35)), 0.55, 1.6);\n        c.off[k] = rng.uniform(-0.5, 0.5);\n    }\n    return c;\n}\n\nbool better_init_sol(const State& s1, int l1, const State& s2, int l2) {\n    if (s1.rawScore != s2.rawScore) return s1.rawScore > s2.rawScore;\n    if (s1.overflow != s2.overflow) return s1.overflow < s2.overflow;\n    if (s1.mass10 != s2.mass10) return s1.mass10 > s2.mass10;\n    if (s1.smallCount != s2.smallCount) return s1.smallCount > s2.smallCount;\n    return l1 < l2;\n}\n\nvector<pair<int,int>> unique_normals(const vector<Line>& lines) {\n    set<pair<int,int>> s;\n    for (const auto& ln : lines) s.insert(normalize_pair(ln.A, ln.B));\n    return vector<pair<int,int>>(s.begin(), s.end());\n}\n\npair<int,int> combine_normals(pair<int,int> a, pair<int,int> b, int sign) {\n    ll A = (ll)a.first + sign * (ll)b.first;\n    ll B = (ll)a.second + sign * (ll)b.second;\n    auto p = normalize_pair(A, B);\n    if (p.first == 0 && p.second == 0) return random_primitive_large();\n    return p;\n}\n\nuint64_t norm_key(pair<int,int> p) {\n    uint64_t a = (uint32_t)(p.first + 1000000000);\n    uint64_t b = (uint32_t)(p.second + 1000000000);\n    return (a << 32) ^ b;\n}\n\nvoid add_normal(vector<pair<int,int>>& out, unordered_set<uint64_t>& seen, pair<int,int> n) {\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return;\n    uint64_t key = norm_key(n);\n    if (seen.insert(key).second) out.push_back(n);\n}\n\nvoid dedup_normals(vector<pair<int,int>>& v) {\n    vector<pair<int,int>> out;\n    unordered_set<uint64_t> seen;\n    seen.reserve(v.size() * 2 + 3);\n    for (auto n : v) add_normal(out, seen, n);\n    v.swap(out);\n}\n\nint pick_biased_point(const State& st) {\n    int best = rng.next_int(0, N - 1);\n    for (int t = 0; t < 2; t++) {\n        int x = rng.next_int(0, N - 1);\n        if (st.cellSize[st.cell[x]] > st.cellSize[st.cell[best]]) best = x;\n    }\n    return best;\n}\n\nvector<pair<int,int>> make_candidate_normals(const State& st, const vector<Line>& lines, int want) {\n    vector<pair<int,int>> out;\n    unordered_set<uint64_t> seen;\n    seen.reserve(want * 4 + 32);\n\n    vector<pair<int,int>> fixed = {\n        {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {3,1}, {1,3}, {2,3}, {3,2}\n    };\n    for (auto n : fixed) add_normal(out, seen, n);\n\n    auto base = unique_normals(lines);\n    shuffle(base.begin(), base.end(), std::mt19937((uint32_t)rng.next()));\n    for (int i = 0; i < (int)base.size() && (int)out.size() < want; i++) {\n        add_normal(out, seen, base[i]);\n        if ((int)out.size() >= want) break;\n        add_normal(out, seen, normalize_pair(-base[i].second, base[i].first));\n    }\n\n    int m = min(6, (int)base.size());\n    for (int i = 0; i < m && (int)out.size() < want; i++) {\n        for (int j = i + 1; j < m && (int)out.size() < want; j++) {\n            add_normal(out, seen, combine_normals(base[i], base[j], +1));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, combine_normals(base[i], base[j], -1));\n        }\n    }\n\n    {\n        int M = (int)st.cellSize.size();\n        vector<pair<int,int>> top;\n        top.reserve(M);\n        for (int id = 0; id < M; id++) top.push_back({st.cellSize[id], id});\n        sort(top.begin(), top.end(), [&](auto& l, auto& r){ return l.first > r.first; });\n\n        int take = min(4, (int)top.size());\n        vector<int> ids(take);\n        for (int i = 0; i < take; i++) ids[i] = top[i].second;\n\n        vector<ll> sx(take, 0), sy(take, 0);\n        for (int i = 0; i < N; i++) {\n            int c = st.cell[i];\n            for (int j = 0; j < take; j++) {\n                if (ids[j] == c) {\n                    sx[j] += pts[i].x;\n                    sy[j] += pts[i].y;\n                    break;\n                }\n            }\n        }\n        for (int i = 0; i < take && (int)out.size() < want; i++) {\n            for (int j = i + 1; j < take && (int)out.size() < want; j++) {\n                ll dx = sx[j] * st.cellSize[ids[i]] - sx[i] * st.cellSize[ids[j]];\n                ll dy = sy[j] * st.cellSize[ids[i]] - sy[i] * st.cellSize[ids[j]];\n                add_normal(out, seen, normalize_pair(dx, dy));\n                if ((int)out.size() >= want) break;\n                add_normal(out, seen, normalize_pair(-dy, dx));\n            }\n        }\n    }\n\n    for (int t = 0; t < 6 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int ci = st.cell[i];\n        int j = -1;\n        for (int rep = 0; rep < 14; rep++) {\n            int x = rng.next_int(0, N - 1);\n            if (x != i && st.cell[x] == ci) {\n                j = x;\n                break;\n            }\n        }\n        if (j != -1) {\n            int dx = pts[j].x - pts[i].x;\n            int dy = pts[j].y - pts[i].y;\n            add_normal(out, seen, normalize_pair(dx, dy));\n            if ((int)out.size() >= want) break;\n            add_normal(out, seen, normalize_pair(-dy, dx));\n        }\n    }\n\n    for (int t = 0; t < 8 && (int)out.size() < want; t++) {\n        int i = pick_biased_point(st);\n        int j = pick_biased_point(st);\n        if (i == j) continue;\n        int dx = pts[j].x - pts[i].x;\n        int dy = pts[j].y - pts[i].y;\n        add_normal(out, seen, normalize_pair(dx, dy));\n        if ((int)out.size() >= want) break;\n        add_normal(out, seen, normalize_pair(-dy, dx));\n    }\n\n    while ((int)out.size() < want) add_normal(out, seen, random_primitive_large());\n    return out;\n}\n\nBestLineRes best_line_for_normal(const State& st, pair<int,int> n) {\n    BestLineRes res;\n    n = normalize_pair(n.first, n.second);\n    if (n.first == 0 && n.second == 0) return res;\n\n    static vector<pair<ll,int>> ord;\n    static vector<int> negCnt, tmpCnt, touched;\n\n    ord.resize(N);\n    for (int i = 0; i < N; i++) ord[i] = {proj(n.first, n.second, pts[i]), i};\n    sort(ord.begin(), ord.end());\n\n    int M = (int)st.cellSize.size();\n    negCnt.assign(M, 0);\n    tmpCnt.assign(M, 0);\n    touched.clear();\n\n    auto hist = st.hist;\n    int small = st.smallCount;\n    int mass10 = st.mass10;\n\n    int bestRaw = st.rawScore;\n    int bestOv = st.overflow;\n    int bestMass = st.mass10;\n    int bestSmall = st.smallCount;\n    ll bestC = 0;\n    bool found = false;\n\n    int i = 0;\n    while (i < N) {\n        ll u = ord[i].first;\n        touched.clear();\n        int j = i;\n        while (j < N && ord[j].first == u) {\n            int id = st.cell[ord[j].second];\n            if (tmpCnt[id] == 0) touched.push_back(id);\n            tmpCnt[id]++;\n            j++;\n        }\n\n        for (int id : touched) {\n            int r = tmpCnt[id];\n            tmpCnt[id] = 0;\n\n            int s = st.cellSize[id];\n            int k = negCnt[id];\n            int p = s - k;\n\n            if (1 <= k && k <= 10) hist[k]--;\n            if (1 <= p && p <= 10) hist[p]--;\n\n            small -= (1 <= k && k <= 10);\n            small -= (1 <= p && p <= 10);\n            mass10 -= min(k, 10);\n            mass10 -= min(p, 10);\n\n            int k2 = k + r;\n            int p2 = s - k2;\n            negCnt[id] = k2;\n\n            if (1 <= k2 && k2 <= 10) hist[k2]++;\n            if (1 <= p2 && p2 <= 10) hist[p2]++;\n\n            small += (1 <= k2 && k2 <= 10);\n            small += (1 <= p2 && p2 <= 10);\n            mass10 += min(k2, 10);\n            mass10 += min(p2, 10);\n        }\n\n        if (j < N && ord[j].first > u + 1) {\n            int raw = compute_raw_from_hist(hist);\n            int ov = compute_overflow_from_hist(hist);\n            if (better_metrics(raw, ov, mass10, small, bestRaw, bestOv, bestMass, bestSmall)) {\n                bestRaw = raw;\n                bestOv = ov;\n                bestMass = mass10;\n                bestSmall = small;\n                bestC = u + 1;\n                found = true;\n            }\n        }\n        i = j;\n    }\n\n    if (!found) return res;\n    res.ok = true;\n    res.raw = bestRaw;\n    res.overflow = bestOv;\n    res.mass10 = bestMass;\n    res.small = bestSmall;\n    res.line = Line{n.first, n.second, bestC};\n    return res;\n}\n\nbool try_add_one_exact(State& cur, vector<Line>& curLines, int wantNormals) {\n    if ((int)curLines.size() >= K) return false;\n\n    auto cands = make_candidate_normals(cur, curLines, wantNormals);\n\n    BestLineRes best;\n    best.raw = cur.rawScore;\n    best.overflow = cur.overflow;\n    best.mass10 = cur.mass10;\n    best.small = cur.smallCount;\n\n    for (auto n : cands) {\n        auto r = best_line_for_normal(cur, n);\n        if (!r.ok) continue;\n        if (better_metrics(r.raw, r.overflow, r.mass10, r.small,\n                           best.raw, best.overflow, best.mass10, best.small)) {\n            best = r;\n        }\n    }\n\n    if (best.ok && best.raw > cur.rawScore) {\n        apply_line(cur, best.line);\n        curLines.push_back(best.line);\n        return true;\n    }\n    return false;\n}\n\nvector<BestLineRes> top_setup_lines(const State& cur, const vector<Line>& curLines, int wantNormals, int topK) {\n    auto cands = make_candidate_normals(cur, curLines, wantNormals);\n    vector<BestLineRes> res;\n\n    for (auto n : cands) {\n        auto r = best_line_for_normal(cur, n);\n        if (!r.ok) continue;\n        if (r.raw != cur.rawScore) continue;\n        if (!better_metrics(r.raw, r.overflow, r.mass10, r.small,\n                            cur.rawScore, cur.overflow, cur.mass10, cur.smallCount)) continue;\n\n        bool strong =\n            (r.overflow < cur.overflow) ||\n            (r.mass10 >= cur.mass10 + 8) ||\n            (r.small >= cur.smallCount + 2);\n        if (!strong) continue;\n\n        res.push_back(r);\n    }\n\n    sort(res.begin(), res.end(), [&](const BestLineRes& a, const BestLineRes& b) {\n        if (a.raw != b.raw) return a.raw > b.raw;\n        if (a.overflow != b.overflow) return a.overflow < b.overflow;\n        if (a.mass10 != b.mass10) return a.mass10 > b.mass10;\n        if (a.small != b.small) return a.small > b.small;\n        if (a.line.A != b.line.A) return a.line.A < b.line.A;\n        if (a.line.B != b.line.B) return a.line.B < b.line.B;\n        return a.line.C < b.line.C;\n    });\n\n    vector<BestLineRes> out;\n    for (auto &x : res) {\n        bool dup = false;\n        for (auto &y : out) {\n            if (x.line.A == y.line.A && x.line.B == y.line.B && x.line.C == y.line.C) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) out.push_back(x);\n        if ((int)out.size() >= topK) break;\n    }\n    return out;\n}\n\nbool try_two_step_setup(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if ((int)curLines.size() + 2 > K) return false;\n    if (timer.elapsed() >= endTime) return false;\n\n    auto setups = top_setup_lines(cur, curLines, 18, 3);\n    if (setups.empty()) return false;\n\n    bool found = false;\n    BestLineRes bestFinal;\n    Line bestFirst{};\n    State bestTmp;\n\n    bestFinal.raw = cur.rawScore;\n    bestFinal.overflow = cur.overflow;\n    bestFinal.mass10 = cur.mass10;\n    bestFinal.small = cur.smallCount;\n\n    for (auto &s : setups) {\n        if (timer.elapsed() >= endTime) break;\n\n        State tmp = cur;\n        vector<Line> tmpLines = curLines;\n        apply_line(tmp, s.line);\n        tmpLines.push_back(s.line);\n\n        auto cands2 = make_candidate_normals(tmp, tmpLines, 14);\n        BestLineRes best2;\n        best2.raw = tmp.rawScore;\n        best2.overflow = tmp.overflow;\n        best2.mass10 = tmp.mass10;\n        best2.small = tmp.smallCount;\n\n        for (auto n : cands2) {\n            if (timer.elapsed() >= endTime) break;\n            auto r = best_line_for_normal(tmp, n);\n            if (!r.ok) continue;\n            if (better_metrics(r.raw, r.overflow, r.mass10, r.small,\n                               best2.raw, best2.overflow, best2.mass10, best2.small)) {\n                best2 = r;\n            }\n        }\n\n        if (best2.ok && best2.raw > cur.rawScore) {\n            if (!found || better_metrics(best2.raw, best2.overflow, best2.mass10, best2.small,\n                                         bestFinal.raw, bestFinal.overflow, bestFinal.mass10, bestFinal.small)) {\n                found = true;\n                bestFinal = best2;\n                bestFirst = s.line;\n                bestTmp = std::move(tmp);\n            }\n        }\n    }\n\n    if (!found) return false;\n    cur = std::move(bestTmp);\n    curLines.push_back(bestFirst);\n    apply_line(cur, bestFinal.line);\n    curLines.push_back(bestFinal.line);\n    return true;\n}\n\nbool prune_once(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n    vector<int> order(curLines.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int idx : order) {\n        if (timer.elapsed() >= endTime) break;\n        State base = build_state_excluding(curLines, idx);\n\n        if (better_metrics(base.rawScore, base.overflow, base.mass10, base.smallCount,\n                           cur.rawScore, cur.overflow, cur.mass10, cur.smallCount) ||\n            same_metrics(base.rawScore, base.overflow, base.mass10, base.smallCount,\n                         cur.rawScore, cur.overflow, cur.mass10, cur.smallCount)) {\n            cur = std::move(base);\n            curLines.erase(curLines.begin() + idx);\n            return true;\n        }\n    }\n    return false;\n}\n\nbool retune_pass(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n    bool changed = false;\n\n    vector<int> order(curLines.size());\n    iota(order.begin(), order.end(), 0);\n    shuffle(order.begin(), order.end(), std::mt19937((uint32_t)rng.next()));\n\n    for (int idx : order) {\n        if (timer.elapsed() >= endTime) break;\n        if (idx >= (int)curLines.size()) continue;\n\n        State base = build_state_excluding(curLines, idx);\n        auto n = normalize_pair(curLines[idx].A, curLines[idx].B);\n        auto r = best_line_for_normal(base, n);\n        if (!r.ok) continue;\n\n        if (better_metrics(r.raw, r.overflow, r.mass10, r.small,\n                           cur.rawScore, cur.overflow, cur.mass10, cur.smallCount)) {\n            curLines[idx] = r.line;\n            cur = std::move(base);\n            apply_line(cur, r.line);\n            changed = true;\n        }\n    }\n    return changed;\n}\n\nbool replace_once(State& cur, vector<Line>& curLines, const Timer& timer, double endTime) {\n    if (curLines.empty()) return false;\n\n    int L = (int)curLines.size();\n    vector<int> candIdx;\n    vector<char> used(L, 0);\n\n    for (int i = max(0, L - 6); i < L; i++) {\n        used[i] = 1;\n        candIdx.push_back(i);\n    }\n    while ((int)candIdx.size() < min(L, 10)) {\n        int x = rng.next_int(0, L - 1);\n        if (!used[x]) {\n            used[x] = 1;\n            candIdx.push_back(x);\n        }\n    }\n\n    int bestIdx = -1;\n    State bestBase;\n    BestLineRes bestMove;\n    bestMove.raw = cur.rawScore;\n    bestMove.overflow = cur.overflow;\n    bestMove.mass10 = cur.mass10;\n    bestMove.small = cur.smallCount;\n\n    for (int idx : candIdx) {\n        if (timer.elapsed() >= endTime) break;\n\n        State base = build_state_excluding(curLines, idx);\n\n        if (better_metrics(base.rawScore, base.overflow, base.mass10, base.smallCount,\n                           cur.rawScore, cur.overflow, cur.mass10, cur.smallCount) ||\n            same_metrics(base.rawScore, base.overflow, base.mass10, base.smallCount,\n                         cur.rawScore, cur.overflow, cur.mass10, cur.smallCount)) {\n            cur = std::move(base);\n            curLines.erase(curLines.begin() + idx);\n            return true;\n        }\n\n        vector<Line> tempLines;\n        tempLines.reserve(L - 1);\n        for (int i = 0; i < L; i++) if (i != idx) tempLines.push_back(curLines[i]);\n\n        auto cands = make_candidate_normals(base, tempLines, 14);\n        auto oldn = normalize_pair(curLines[idx].A, curLines[idx].B);\n        cands.push_back(oldn);\n        cands.push_back(normalize_pair(-oldn.second, oldn.first));\n        dedup_normals(cands);\n\n        for (auto n : cands) {\n            if (timer.elapsed() >= endTime) break;\n            auto r = best_line_for_normal(base, n);\n            if (!r.ok) continue;\n            if (better_metrics(r.raw, r.overflow, r.mass10, r.small,\n                               bestMove.raw, bestMove.overflow, bestMove.mass10, bestMove.small)) {\n                bestMove = r;\n                bestIdx = idx;\n                bestBase = base;\n            }\n        }\n    }\n\n    if (bestIdx != -1 &&\n        better_metrics(bestMove.raw, bestMove.overflow, bestMove.mass10, bestMove.small,\n                       cur.rawScore, cur.overflow, cur.mass10, cur.smallCount)) {\n        curLines[bestIdx] = bestMove.line;\n        cur = std::move(bestBase);\n        apply_line(cur, bestMove.line);\n        return true;\n    }\n    return false;\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = (a >= 0 ? 1 : -1);\n        y = 0;\n        return std::llabs(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\nll modinv(ll a, ll mod) {\n    if (mod == 1) return 0;\n    ll x, y;\n    ll g = extgcd(a, mod, x, y);\n    if (g != 1) return 0;\n    x %= mod;\n    if (x < 0) x += mod;\n    return x;\n}\n\narray<ll,4> line_to_points(const Line& ln) {\n    const ll LIM = 1000000000LL - 5;\n    ll A = ln.A, B = ln.B, C = ln.C;\n\n    if (B == 0) {\n        ll x = C / A;\n        return {x, -LIM, x, LIM};\n    }\n    if (A == 0) {\n        ll y = C / B;\n        return {-LIM, y, LIM, y};\n    }\n\n    ll b = std::llabs(B);\n    ll a = ((A % b) + b) % b;\n    ll c = ((C % b) + b) % b;\n    ll inv = modinv(a, b);\n    ll x0 = (ll)((__int128)inv * c % b);\n    ll y0 = (C - A * x0) / B;\n\n    ll t1 = (LIM - std::llabs(x0)) / std::llabs(B);\n    ll t2 = (LIM - std::llabs(y0)) / std::llabs(A);\n    ll t = min(t1, t2);\n    t = min<ll>(t, 200000);\n    if (t < 1) t = 1;\n\n    ll x1 = x0 - B * t;\n    ll y1 = y0 + A * t;\n    ll x2 = x0 + B * t;\n    ll y2 = y0 - A * t;\n\n    while ((std::llabs(x1) > LIM || std::llabs(y1) > LIM ||\n            std::llabs(x2) > LIM || std::llabs(y2) > LIM) && t > 1) {\n        t /= 2;\n        x1 = x0 - B * t;\n        y1 = y0 + A * t;\n        x2 = x0 + B * t;\n        y2 = y0 - A * t;\n    }\n    return {x1, y1, x2, y2};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K;\n    uint64_t seed = 0x123456789abcdef0ull;\n\n    seed ^= splitmix64((uint64_t)N);\n    seed ^= splitmix64((uint64_t)K);\n\n    for (int d = 1; d <= 10; d++) {\n        cin >> a_need[d];\n        attendees_sum += a_need[d];\n        seed ^= splitmix64((uint64_t)(a_need[d] + 1000 * d + 1));\n    }\n\n    pts.resize(N);\n    for (int i = 0; i < N; i++) {\n        cin >> pts[i].x >> pts[i].y;\n        uint64_t v1 = (uint64_t)(pts[i].x + 20000);\n        uint64_t v2 = (uint64_t)(pts[i].y + 20000);\n        seed ^= splitmix64((v1 << 21) ^ v2 ^ (uint64_t)i * 0x9e3779b97f4a7c15ull);\n    }\n    rng = XorShift64(splitmix64(seed));\n\n    Timer timer;\n\n    const double INITIAL_END = 0.82;\n    const double AUG1_END    = 1.60;\n    const double MID_END     = 2.35;\n    const double REPL_END    = 2.88;\n    const double FINAL_END   = 2.96;\n\n    double lambdaStar = estimate_lambda_star();\n    double lambdaAvg = max(1.0, (double)N / attendees_sum);\n\n    vector<Line> bestLines;\n    State bestState = build_state({});\n    bestLines.clear();\n\n    // Deterministic 2-bundle seeds, including anisotropic aspect ratios.\n    {\n        vector<pair<int,int>> seedNormals = {\n            {1,0}, {0,1}, {1,1}, {1,-1}, {2,1}, {1,2}, {3,1}, {1,3}\n        };\n        vector<double> lams = {\n            clampv(lambdaStar * 0.85, 1.0, 12.0),\n            clampv(lambdaStar,        1.0, 12.0),\n            clampv(lambdaStar * 1.15, 1.0, 12.0),\n            clampv(lambdaAvg,         1.0, 12.0),\n        };\n        vector<double> alphas = {0.90, 1.00, 1.10};\n        vector<double> offs = {0.0, 0.25};\n        vector<double> aspects = {1.0, 1.8, 1.0 / 1.8};\n\n        for (auto n0 : seedNormals) {\n            auto n = normalize_pair(n0.first, n0.second);\n            for (double lam : lams) {\n                for (double alpha : alphas) {\n                    for (double off : offs) {\n                        for (double asp : aspects) {\n                            Cand2 c;\n                            c.A = n.first;\n                            c.B = n.second;\n                            double Ctarget = N / lam;\n                            double prod = 4.0 * Ctarget / acos(-1.0);\n                            c.t1 = max(1, (int)llround(sqrt(prod * asp) - 1.0));\n                            c.t2 = max(1, (int)llround(sqrt(prod / asp) - 1.0));\n                            while (c.t1 + c.t2 > MAX_CUTS) {\n                                if (c.t1 >= c.t2 && c.t1 > 1) c.t1--;\n                                else if (c.t2 > 1) c.t2--;\n                                else break;\n                            }\n                            c.alpha1 = c.alpha2 = alpha;\n                            c.off1 = off;\n                            c.off2 = -off;\n\n                            auto lines = build_lines2(c);\n                            State st = build_state(lines);\n                            if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                                bestState = st;\n                                bestLines = lines;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    // Random bundled search.\n    while (timer.elapsed() < INITIAL_END) {\n        bool use3 = (rng.next() % 10 < 3);\n        if (!use3) {\n            Cand2 c = random_cand2(lambdaStar);\n            int approx = eval_cand2(c);\n            if (approx + 2 >= bestState.rawScore) {\n                auto lines = build_lines2(c);\n                State st = build_state(lines);\n                if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                    bestState = st;\n                    bestLines = lines;\n                }\n            }\n        } else {\n            Cand3 c = random_cand3(lambdaStar);\n            int approx = eval_cand3(c);\n            if (approx + 2 >= bestState.rawScore) {\n                auto lines = build_lines3(c);\n                State st = build_state(lines);\n                if (better_init_sol(st, (int)lines.size(), bestState, (int)bestLines.size())) {\n                    bestState = st;\n                    bestLines = lines;\n                }\n            }\n        }\n    }\n\n    vector<Line> curLines = bestLines;\n    State cur = bestState;\n\n    // Phase 1: exact augmentation + selective early 2-step setup.\n    {\n        int stall = 0;\n        while ((int)curLines.size() < K && timer.elapsed() < AUG1_END && cur.rawScore < attendees_sum) {\n            bool changed = false;\n            int want = (timer.elapsed() < 1.20 ? 28 : 22);\n            if (try_add_one_exact(cur, curLines, want)) {\n                changed = true;\n            } else if (stall >= 1 && timer.elapsed() < AUG1_END - 0.12) {\n                changed = try_two_step_setup(cur, curLines, timer, AUG1_END - 0.03);\n            }\n\n            if (changed) stall = 0;\n            else {\n                stall++;\n                if (stall >= 4) break;\n            }\n        }\n    }\n\n    // Phase 2: prune + retune.\n    while (timer.elapsed() < MID_END) {\n        bool changed = false;\n\n        if (prune_once(cur, curLines, timer, MID_END)) {\n            changed = true;\n            if (timer.elapsed() < MID_END - 0.05 && (int)curLines.size() < K) {\n                try_add_one_exact(cur, curLines, 18);\n            }\n            continue;\n        }\n\n        if (retune_pass(cur, curLines, timer, MID_END)) {\n            changed = true;\n        }\n\n        if (!changed) break;\n    }\n\n    // Phase 3: replacement neighborhood.\n    {\n        int stall = 0;\n        while (timer.elapsed() < REPL_END && stall < 5) {\n            bool changed = replace_once(cur, curLines, timer, REPL_END);\n            if (changed) {\n                stall = 0;\n                if (timer.elapsed() < REPL_END - 0.05 && (int)curLines.size() < K) {\n                    try_add_one_exact(cur, curLines, 16);\n                }\n            } else {\n                stall++;\n            }\n        }\n    }\n\n    // Phase 4: final exact augmentation.\n    {\n        int stall = 0;\n        while ((int)curLines.size() < K && timer.elapsed() < FINAL_END && cur.rawScore < attendees_sum) {\n            if (try_add_one_exact(cur, curLines, 18)) stall = 0;\n            else {\n                stall++;\n                if (stall >= 4) break;\n            }\n        }\n    }\n\n    cout << curLines.size() << '\\n';\n    for (const auto& ln : curLines) {\n        auto p = line_to_points(ln);\n        cout << p[0] << ' ' << p[1] << ' ' << p[2] << ' ' << p[3] << '\\n';\n    }\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 61;\nstatic constexpr int MAXID = MAXN * MAXN;\nstatic constexpr int MAXD = 2 * MAXN - 1;\nstatic constexpr double EPS = 1e-12;\n\nint GX[MAXID], GY[MAXID];\ninline int enc(int x, int y) { return y * MAXN + x; }\n\nstruct CoordInit {\n    CoordInit() {\n        for (int y = 0; y < MAXN; ++y) {\n            for (int x = 0; x < MAXN; ++x) {\n                int id = enc(x, y);\n                GX[id] = x;\n                GY[id] = y;\n            }\n        }\n    }\n} coord_init;\n\nstruct Operation {\n    int x1, y1, x2, y2, x3, y3, x4, y4;\n};\n\nstruct Candidate {\n    Operation op;\n    double key;\n    int gain;\n    int cost1;\n    int cost2;\n};\n\nstruct Params {\n    double lambda0, lambda1;\n    double quad0, quad1;\n    int topK;\n    int randDepth;\n};\n\nclass Solver {\n    enum Dir {\n        LEFT = 0, RIGHT = 1, DOWN = 2, UP = 3,\n        NE = 4, NW = 5, SW = 6, SE = 7\n    };\n\n    static constexpr int KEEP = 48;\n\n    int N, M, c;\n    int phaseLen;\n\n    vector<int> cellOrder;\n    vector<pair<int,int>> initPts;\n\n    array<pair<int,int>, 8> pairs{\n        pair<int,int>{LEFT, DOWN},\n        pair<int,int>{LEFT, UP},\n        pair<int,int>{RIGHT, DOWN},\n        pair<int,int>{RIGHT, UP},\n        pair<int,int>{NE, NW},\n        pair<int,int>{NE, SE},\n        pair<int,int>{SW, NW},\n        pair<int,int>{SW, SE}\n    };\n\n    int weight[MAXN][MAXN]{};\n\n    // initial dot masks\n    uint64_t initRow[MAXN]{}, initCol[MAXN]{}, initD1[MAXD]{}, initD2[MAXD]{};\n\n    // current dot masks\n    uint64_t rowMask[MAXN]{}, colMask[MAXN]{}, d1Mask[MAXD]{}, d2Mask[MAXD]{};\n\n    // used unit-segment masks\n    uint64_t useH[MAXN]{}, useV[MAXN]{}, useSegD1[MAXD]{}, useSegD2[MAXD]{};\n\n    long long initialWeight = 0;\n    long long curWeight = 0;\n    long long bestWeight = 0;\n\n    vector<Operation> ops;\n    vector<Operation> bestOps;\n\n    mt19937_64 rng;\n\n    inline bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    inline bool hasDot(int x, int y) const {\n        return (rowMask[y] >> x) & 1ULL;\n    }\n\n    static inline int prevBit(uint64_t mask, int pos) {\n        if (pos <= 0) return -1;\n        uint64_t m = mask & ((1ULL << pos) - 1);\n        if (!m) return -1;\n        return 63 - __builtin_clzll(m);\n    }\n\n    static inline int nextBit(uint64_t mask, int pos) {\n        if (pos >= 63) return -1;\n        uint64_t lower = (1ULL << (pos + 1)) - 1;\n        uint64_t m = mask & ~lower;\n        if (!m) return -1;\n        return __builtin_ctzll(m);\n    }\n\n    inline int queryDir(int dir, int x, int y) const {\n        int p, xx, yy;\n        switch (dir) {\n            case LEFT:\n                p = prevBit(rowMask[y], x);\n                return (p < 0 ? -1 : enc(p, y));\n            case RIGHT:\n                p = nextBit(rowMask[y], x);\n                return (p < 0 ? -1 : enc(p, y));\n            case DOWN:\n                p = prevBit(colMask[x], y);\n                return (p < 0 ? -1 : enc(x, p));\n            case UP:\n                p = nextBit(colMask[x], y);\n                return (p < 0 ? -1 : enc(x, p));\n            case SW: {\n                int d = x - y;\n                p = prevBit(d1Mask[d + N - 1], x);\n                if (p < 0) return -1;\n                xx = p;\n                yy = xx - d;\n                return enc(xx, yy);\n            }\n            case NE: {\n                int d = x - y;\n                p = nextBit(d1Mask[d + N - 1], x);\n                if (p < 0) return -1;\n                xx = p;\n                yy = xx - d;\n                return enc(xx, yy);\n            }\n            case NW: {\n                int s = x + y;\n                p = prevBit(d2Mask[s], x);\n                if (p < 0) return -1;\n                xx = p;\n                yy = s - xx;\n                return enc(xx, yy);\n            }\n            case SE: {\n                int s = x + y;\n                p = nextBit(d2Mask[s], x);\n                if (p < 0) return -1;\n                xx = p;\n                yy = s - xx;\n                return enc(xx, yy);\n            }\n        }\n        return -1;\n    }\n\n    static bool betterCand(const Candidate& a, const Candidate& b) {\n        if (a.key > b.key + EPS) return true;\n        if (a.key + EPS < b.key) return false;\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.cost2 != b.cost2) return a.cost2 < b.cost2;\n        if (a.cost1 != b.cost1) return a.cost1 < b.cost1;\n        return false;\n    }\n\n    void consider(vector<Candidate>& top, const Candidate& cand, int keep) {\n        int pos = (int)top.size();\n        while (pos > 0 && betterCand(cand, top[pos - 1])) --pos;\n        if (pos >= keep) return;\n        top.insert(top.begin() + pos, cand);\n        if ((int)top.size() > keep) top.pop_back();\n    }\n\n    int chooseIndex(int lim) {\n        if (lim <= 1) return 0;\n        uint64_t sum = (uint64_t)lim * (lim + 1) / 2;\n        uint64_t r = rng() % sum;\n        uint64_t acc = 0;\n        for (int i = 0; i < lim; ++i) {\n            acc += (uint64_t)(lim - i);\n            if (r < acc) return i;\n        }\n        return 0;\n    }\n\n    inline uint64_t rangeMask(int l, int r) const {\n        if (l >= r) return 0;\n        return ((1ULL << r) - 1) ^ ((1ULL << l) - 1);\n    }\n\n    inline bool usedOnSeg(int x1, int y1, int x2, int y2) const {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            return (useH[y1] & rangeMask(l, r)) != 0;\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            return (useV[x1] & rangeMask(l, r)) != 0;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + N - 1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (useSegD1[d] & rangeMask(l, r)) != 0;\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            return (useSegD2[s] & rangeMask(l, r)) != 0;\n        }\n    }\n\n    inline void markSeg(int x1, int y1, int x2, int y2) {\n        if (y1 == y2) {\n            int l = min(x1, x2), r = max(x1, x2);\n            useH[y1] |= rangeMask(l, r);\n            return;\n        }\n        if (x1 == x2) {\n            int l = min(y1, y2), r = max(y1, y2);\n            useV[x1] |= rangeMask(l, r);\n            return;\n        }\n        if ((x2 - x1) == (y2 - y1)) {\n            int d = x1 - y1 + N - 1;\n            int l = min(x1, x2), r = max(x1, x2);\n            useSegD1[d] |= rangeMask(l, r);\n        } else {\n            int s = x1 + y1;\n            int l = min(x1, x2), r = max(x1, x2);\n            useSegD2[s] |= rangeMask(l, r);\n        }\n    }\n\n    inline void addDot(int x, int y) {\n        rowMask[y] |= 1ULL << x;\n        colMask[x] |= 1ULL << y;\n        d1Mask[x - y + N - 1] |= 1ULL << x;\n        d2Mask[x + y] |= 1ULL << x;\n        curWeight += weight[x][y];\n    }\n\n    void apply(const Candidate& cand) {\n        const auto& o = cand.op;\n        addDot(o.x1, o.y1);\n        markSeg(o.x1, o.y1, o.x2, o.y2);\n        markSeg(o.x2, o.y2, o.x3, o.y3);\n        markSeg(o.x3, o.y3, o.x4, o.y4);\n        markSeg(o.x4, o.y4, o.x1, o.y1);\n        ops.push_back(o);\n    }\n\n    double interp(double a, double b, int step) const {\n        if (step >= phaseLen) return b;\n        double t = double(phaseLen - step) / phaseLen;\n        return b + (a - b) * t;\n    }\n\n    void resetState() {\n        memcpy(rowMask, initRow, sizeof(initRow));\n        memcpy(colMask, initCol, sizeof(initCol));\n        memcpy(d1Mask, initD1, sizeof(initD1));\n        memcpy(d2Mask, initD2, sizeof(initD2));\n        memset(useH, 0, sizeof(useH));\n        memset(useV, 0, sizeof(useV));\n        memset(useSegD1, 0, sizeof(useSegD1));\n        memset(useSegD2, 0, sizeof(useSegD2));\n        curWeight = initialWeight;\n        ops.clear();\n    }\n\n    vector<Candidate> collectTop(double lambda, double quad, int keep) {\n        vector<Candidate> top;\n        top.reserve(keep);\n\n        for (int id1 : cellOrder) {\n            int x = GX[id1], y = GY[id1];\n            if (hasDot(x, y)) continue;\n\n            int gain = weight[x][y];\n            if ((int)top.size() == keep) {\n                double upper = gain - lambda * 2.0 - quad * 2.0; // min possible penalty\n                if (upper + EPS < top.back().key) break;\n            }\n\n            int near[8];\n            for (int d = 0; d < 8; ++d) near[d] = queryDir(d, x, y);\n\n            for (auto [da, db] : pairs) {\n                int id2 = near[da];\n                int id4 = near[db];\n                if (id2 < 0 || id4 < 0) continue;\n\n                int x2 = GX[id2], y2 = GY[id2];\n                int x4 = GX[id4], y4 = GY[id4];\n\n                int x3 = x2 + x4 - x;\n                int y3 = y2 + y4 - y;\n                if (!inside(x3, y3)) continue;\n                if (!hasDot(x3, y3)) continue;\n\n                int id3 = enc(x3, y3);\n\n                // no extra dots on perimeter\n                if (queryDir(db, x2, y2) != id3) continue;\n                if (queryDir(da, x4, y4) != id3) continue;\n\n                // no positive-length overlap with already drawn edges\n                if (usedOnSeg(x, y, x2, y2)) continue;\n                if (usedOnSeg(x2, y2, x3, y3)) continue;\n                if (usedOnSeg(x3, y3, x4, y4)) continue;\n                if (usedOnSeg(x4, y4, x, y)) continue;\n\n                int len1 = max(abs(x2 - x), abs(y2 - y));\n                int len2 = max(abs(x4 - x), abs(y4 - y));\n                int cost1 = len1 + len2;\n                int cost2 = len1 * len1 + len2 * len2;\n\n                Candidate cand{\n                    Operation{x, y, x2, y2, x3, y3, x4, y4},\n                    gain - lambda * cost1 - quad * cost2,\n                    gain,\n                    cost1,\n                    cost2\n                };\n                consider(top, cand, keep);\n            }\n        }\n\n        return top;\n    }\n\n    void runAttempt(const Params& prm,\n                    chrono::steady_clock::time_point deadline,\n                    const vector<int>& forcedRanks = {}) {\n        resetState();\n        int step = 0;\n\n        while (true) {\n            if (chrono::steady_clock::now() >= deadline) break;\n\n            double lambda = interp(prm.lambda0, prm.lambda1, step);\n            double quad = interp(prm.quad0, prm.quad1, step);\n            auto top = collectTop(lambda, quad, KEEP);\n            if (top.empty()) break;\n\n            int idx = 0;\n            if (step < (int)forcedRanks.size()) {\n                idx = min(forcedRanks[step], (int)top.size() - 1);\n            } else if (step < prm.randDepth && prm.topK > 1) {\n                idx = chooseIndex(min(prm.topK, (int)top.size()));\n            }\n\n            apply(top[idx]);\n            ++step;\n        }\n\n        if (curWeight > bestWeight) {\n            bestWeight = curWeight;\n            bestOps = ops;\n        }\n    }\n\n    int rootTopCount(const Params& prm, int cap) {\n        resetState();\n        auto top = collectTop(interp(prm.lambda0, prm.lambda1, 0),\n                              interp(prm.quad0, prm.quad1, 0), cap);\n        return (int)top.size();\n    }\n\npublic:\n    Solver(int N_, int M_, const vector<pair<int,int>>& pts) : N(N_), M(M_), c((N_ - 1) / 2) {\n        phaseLen = max(18, min(40, N));\n\n        uint64_t seed = 0x9e3779b97f4a7c15ULL;\n        auto mix = [&](uint64_t v) {\n            seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        };\n        mix((uint64_t)N);\n        mix((uint64_t)M);\n        for (auto [x, y] : pts) {\n            mix((uint64_t)(x + 1) * 1000003ULL + (uint64_t)(y + 7) * 1000033ULL);\n        }\n        rng.seed(seed);\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                weight[x][y] = (x - c) * (x - c) + (y - c) * (y - c) + 1;\n                cellOrder.push_back(enc(x, y));\n            }\n        }\n\n        stable_sort(cellOrder.begin(), cellOrder.end(), [&](int a, int b) {\n            int xa = GX[a], ya = GY[a];\n            int xb = GX[b], yb = GY[b];\n            if (weight[xa][ya] != weight[xb][yb]) return weight[xa][ya] > weight[xb][yb];\n            int ma = max(abs(xa - c), abs(ya - c));\n            int mb = max(abs(xb - c), abs(yb - c));\n            if (ma != mb) return ma > mb;\n            int sa = abs(xa - c) + abs(ya - c);\n            int sb = abs(xb - c) + abs(yb - c);\n            if (sa != sb) return sa > sb;\n            return a < b;\n        });\n\n        memset(initRow, 0, sizeof(initRow));\n        memset(initCol, 0, sizeof(initCol));\n        memset(initD1, 0, sizeof(initD1));\n        memset(initD2, 0, sizeof(initD2));\n\n        for (auto [x, y] : pts) {\n            initPts.push_back({x, y});\n            initRow[y] |= 1ULL << x;\n            initCol[x] |= 1ULL << y;\n            initD1[x - y + N - 1] |= 1ULL << x;\n            initD2[x + y] |= 1ULL << x;\n            initialWeight += weight[x][y];\n        }\n\n        curWeight = bestWeight = initialWeight;\n        ops.reserve(N * N);\n        bestOps.reserve(N * N);\n    }\n\n    void solve() {\n        auto start = chrono::steady_clock::now();\n        auto deadline = start + chrono::milliseconds(4700);\n\n        double density = double(M) / double(N * N);\n        double base = 6.0 + (0.05 - density) * 30.0;\n        base = max(3.0, min(8.0, base));\n\n        vector<Params> fixed = {\n            {20.0, 20.0, 0.0, 0.0, 1, 0},\n            {12.0, 12.0, 0.0, 0.0, 1, 0},\n            { 8.0,  8.0, 0.0, 0.0, 1, 0},\n            { 6.0,  6.0, 0.0, 0.0, 1, 0},\n            { 4.0,  4.0, 0.0, 0.0, 1, 0},\n            { 2.0,  2.0, 0.0, 0.0, 1, 0},\n            { 1.0,  1.0, 0.0, 0.0, 1, 0},\n            { 0.5,  0.5, 0.0, 0.0, 1, 0},\n            { 0.25, 0.25,0.0, 0.0, 1, 0},\n            { 0.0,  0.0, 0.0, 0.0, 1, 0},\n\n            {12.0,  2.0, 0.0, 0.0, 1, 0},\n            { 8.0,  1.0, 0.0, 0.0, 1, 0},\n            { 6.0,  0.5, 0.0, 0.0, 1, 0},\n            { 4.0,  0.0, 0.0, 0.0, 1, 0},\n            { 3.0,  0.0, 0.0, 0.0, 1, 0},\n            { 2.0,  0.0, 0.0, 0.0, 1, 0},\n\n            { base + 1.0, base * 0.30, 0.0, 0.0, 1, 0},\n            { base,       0.0,        0.0, 0.0, 1, 0},\n\n            { 8.0,  1.0, 0.10, 0.0, 1, 0},\n            { 6.0,  0.5, 0.08, 0.0, 1, 0},\n            { 4.0,  0.0, 0.15, 0.0, 1, 0},\n\n            { 6.0,  0.5, 0.0, 0.0, 3,  8},\n            { 4.0,  0.0, 0.0, 0.0, 4, 10},\n            { 2.0,  0.0, 0.0, 0.0, 6, 16},\n            { 1.0,  0.0, 0.0, 0.0, 8, 24},\n            { 0.5,  0.0, 0.0, 0.0,10, 32},\n            { 0.0,  0.0, 0.0, 0.0,10, 40}\n        };\n\n        for (const auto& prm : fixed) {\n            if (chrono::steady_clock::now() >= deadline) break;\n            runAttempt(prm, deadline);\n        }\n\n        // first-move exploration\n        vector<Params> prefixParams = {\n            {8.0, 1.0, 0.0, 0.0, 1, 0},\n            {6.0, 0.5, 0.0, 0.0, 1, 0},\n            {4.0, 0.0, 0.0, 0.0, 1, 0},\n            {2.0, 0.0, 0.0, 0.0, 1, 0}\n        };\n\n        for (const auto& prm : prefixParams) {\n            if (chrono::steady_clock::now() + chrono::milliseconds(140) >= deadline) break;\n\n            Params rnd = prm;\n            rnd.topK = 4;\n            rnd.randDepth = 12;\n\n            int cnt = rootTopCount(prm, 6);\n            for (int r = 0; r < cnt; ++r) {\n                if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                runAttempt(prm, deadline, {r});\n                if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                runAttempt(rnd, deadline, {r});\n            }\n        }\n\n        // small 2-move exploration\n        {\n            Params prm{4.0, 0.0, 0.0, 0.0, 4, 14};\n            if (chrono::steady_clock::now() + chrono::milliseconds(180) < deadline) {\n                for (int r1 = 0; r1 < 3; ++r1) {\n                    for (int r2 = 0; r2 < 2; ++r2) {\n                        if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                        runAttempt(prm, deadline, {r1, r2});\n                    }\n                    if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                }\n            }\n        }\n        {\n            Params prm{6.0, 0.5, 0.0, 0.0, 4, 12};\n            if (chrono::steady_clock::now() + chrono::milliseconds(160) < deadline) {\n                for (int r1 = 0; r1 < 2; ++r1) {\n                    for (int r2 = 0; r2 < 2; ++r2) {\n                        if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                        runAttempt(prm, deadline, {r1, r2});\n                    }\n                    if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                }\n            }\n        }\n\n        // tiny 3-move exploration\n        {\n            Params prm{4.0, 0.0, 0.0, 0.0, 4, 16};\n            if (chrono::steady_clock::now() + chrono::milliseconds(220) < deadline) {\n                for (int r1 = 0; r1 < 2; ++r1) {\n                    for (int r2 = 0; r2 < 2; ++r2) {\n                        for (int r3 = 0; r3 < 2; ++r3) {\n                            if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                            runAttempt(prm, deadline, {r1, r2, r3});\n                        }\n                        if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                    }\n                    if (chrono::steady_clock::now() + chrono::milliseconds(50) >= deadline) break;\n                }\n            }\n        }\n\n        static const vector<double> L0 = {\n            0.0, 0.25, 0.5, 1.0, 2.0, 3.0, 4.0, 4.0, 6.0, 6.0, 8.0, 8.0, 12.0, 16.0, 20.0\n        };\n        static const vector<double> L1 = {\n            0.0, 0.0, 0.25, 0.5, 1.0, 1.0, 2.0\n        };\n        static const vector<double> Q0 = {\n            0.0, 0.0, 0.0, 0.0, 0.05, 0.10, 0.15, 0.20\n        };\n        static const vector<int> TK = {1, 2, 3, 4, 6, 8, 10, 12};\n        static const vector<int> RD = {0, 4, 8, 12, 16, 24, 32, 48, 64};\n\n        while (chrono::steady_clock::now() < deadline) {\n            Params prm;\n            prm.lambda0 = L0[(size_t)(rng() % L0.size())];\n            prm.lambda1 = L1[(size_t)(rng() % L1.size())];\n            if (prm.lambda1 > prm.lambda0) swap(prm.lambda0, prm.lambda1);\n\n            if ((rng() & 7ULL) == 0) {\n                double b0 = base + (double)((int)(rng() % 4001) - 2000) / 2000.0;\n                b0 = max(0.0, min(12.0, b0));\n                prm.lambda0 = max(prm.lambda0, b0);\n                prm.lambda1 = min(prm.lambda1, b0 * 0.3);\n                if (prm.lambda1 > prm.lambda0) swap(prm.lambda0, prm.lambda1);\n            }\n\n            prm.quad0 = Q0[(size_t)(rng() % Q0.size())];\n            prm.quad1 = 0.0;\n            if ((rng() & 3ULL) == 0) prm.quad0 = 0.0;\n\n            prm.topK = TK[(size_t)(rng() % TK.size())];\n            prm.randDepth = RD[(size_t)(rng() % RD.size())];\n            if (prm.topK == 1) prm.randDepth = 0;\n\n            uint64_t mode = rng() & 31ULL;\n            if (mode == 0) {\n                runAttempt(prm, deadline, {(int)(rng() % 6)});\n            } else if (mode == 1) {\n                runAttempt(prm, deadline, {(int)(rng() % 4), (int)(rng() % 3)});\n            } else if (mode == 2) {\n                runAttempt(prm, deadline, {(int)(rng() % 3), (int)(rng() % 2), (int)(rng() % 2)});\n            } else {\n                runAttempt(prm, deadline);\n            }\n        }\n    }\n\n    void output() const {\n        cout << bestOps.size() << '\\n';\n        for (const auto& o : bestOps) {\n            cout << o.x1 << ' ' << o.y1 << ' '\n                 << o.x2 << ' ' << o.y2 << ' '\n                 << o.x3 << ' ' << o.y3 << ' '\n                 << o.x4 << ' ' << o.y4 << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<pair<int,int>> pts(M);\n    for (int i = 0; i < M; ++i) cin >> pts[i].first >> pts[i].second;\n\n    Solver solver(N, M, pts);\n    solver.solve();\n    solver.output();\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Board {\n    array<uint8_t, 100> a;\n};\n\nstatic constexpr char DIR_CH[4] = {'F', 'B', 'L', 'R'}; // F=up, B=down, L=left, R=right\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n    uint64_t next_u64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n};\n\nclass Solver {\n    static constexpr double TIME_LIMIT = 1.80;\n\n    int flavor[101]{};\n    int totalCnt[4]{};\n    int suffixCnt[103][4]{};\n\n    Board cur{};\n    SplitMix64 rng;\n    chrono::steady_clock::time_point st;\n\n    int perms[6][3] = {\n        {1,2,3}, {1,3,2}, {2,1,3},\n        {2,3,1}, {3,1,2}, {3,2,1}\n    };\n\n    uint8_t pathCell[8][100]{};\n    uint8_t distCost[48][100][4]{}; // [pattern][cell][color]\n    int lastPattern = -1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n\n    static inline void place_by_rank(Board &b, int rank, int f) {\n        for (int i = 0; i < 100; ++i) {\n            if (b.a[i] == 0) {\n                if (--rank == 0) {\n                    b.a[i] = (uint8_t)f;\n                    return;\n                }\n            }\n        }\n    }\n\n    static inline int collect_empties(const Board &b, int out[100]) {\n        int m = 0;\n        for (int i = 0; i < 100; ++i) if (b.a[i] == 0) out[m++] = i;\n        return m;\n    }\n\n    static inline void apply_tilt(const Board &src, int dir, Board &dst) {\n        dst.a.fill(0);\n        if (dir == 0) { // F\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 0;\n                for (int r = 0; r < 10; ++r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[(ptr++) * 10 + c] = v;\n                }\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < 10; ++c) {\n                int ptr = 9;\n                for (int r = 9; r >= 0; --r) {\n                    uint8_t v = src.a[r * 10 + c];\n                    if (v) dst.a[(ptr--) * 10 + c] = v;\n                }\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 0;\n                for (int c = 0; c < 10; ++c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + (ptr++)] = v;\n                }\n            }\n        } else { // R\n            for (int r = 0; r < 10; ++r) {\n                int base = r * 10;\n                int ptr = 9;\n                for (int c = 9; c >= 0; --c) {\n                    uint8_t v = src.a[base + c];\n                    if (v) dst.a[base + (ptr--)] = v;\n                }\n            }\n        }\n    }\n\n    static int comp_sq_only(const Board &b) {\n        uint8_t vis[100] = {};\n        int q[100];\n        int res = 0;\n\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n\n            res += sz * sz;\n        }\n        return res;\n    }\n\n    void init_patterns() {\n        int pid = 0;\n\n        // 4 row snakes\n        for (int fv = 0; fv < 2; ++fv) {\n            for (int fh = 0; fh < 2; ++fh) {\n                int k = 0;\n                for (int r = 0; r < 10; ++r) {\n                    if ((r & 1) == 0) {\n                        for (int c = 0; c < 10; ++c) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    } else {\n                        for (int c = 9; c >= 0; --c) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    }\n                }\n                ++pid;\n            }\n        }\n\n        // 4 col snakes\n        for (int fv = 0; fv < 2; ++fv) {\n            for (int fh = 0; fh < 2; ++fh) {\n                int k = 0;\n                for (int c = 0; c < 10; ++c) {\n                    if ((c & 1) == 0) {\n                        for (int r = 0; r < 10; ++r) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    } else {\n                        for (int r = 9; r >= 0; --r) {\n                            int rr = fv ? 9 - r : r;\n                            int cc = fh ? 9 - c : c;\n                            pathCell[pid][k++] = (uint8_t)(rr * 10 + cc);\n                        }\n                    }\n                }\n                ++pid;\n            }\n        }\n\n        for (int p = 0; p < 8; ++p) {\n            for (int q = 0; q < 6; ++q) {\n                int pat = p * 6 + q;\n                int L[4] = {}, R[4] = {};\n                int curPos = 0;\n                for (int t = 0; t < 3; ++t) {\n                    int c = perms[q][t];\n                    if (totalCnt[c] == 0) {\n                        L[c] = 0;\n                        R[c] = -1;\n                    } else {\n                        L[c] = curPos;\n                        R[c] = curPos + totalCnt[c] - 1;\n                        curPos += totalCnt[c];\n                    }\n                }\n\n                for (int idx = 0; idx < 100; ++idx) {\n                    int cell = pathCell[p][idx];\n                    for (int c = 1; c <= 3; ++c) {\n                        int dist = 0;\n                        if (totalCnt[c] == 0) dist = 0;\n                        else if (idx < L[c]) dist = L[c] - idx;\n                        else if (idx > R[c]) dist = idx - R[c];\n                        else dist = 0;\n                        distCost[pat][cell][c] = (uint8_t)dist;\n                    }\n                }\n            }\n        }\n    }\n\n    inline int pattern_penalty(const Board &b, int pat) const {\n        int sum = 0;\n        for (int i = 0; i < 100; ++i) {\n            uint8_t col = b.a[i];\n            if (col) sum += distCost[pat][i][col];\n        }\n        return sum;\n    }\n\n    int best_pattern_for_board(const Board &b) const {\n        int bestPat = 0;\n        int bestScore = INT_MAX;\n        for (int pat = 0; pat < 48; ++pat) {\n            int s = pattern_penalty(b, pat);\n            if (s < bestScore) {\n                bestScore = s;\n                bestPat = pat;\n            }\n        }\n        return bestPat;\n    }\n\n    int select_active_patterns(const Board cand[4], int active[3]) const {\n        int bestPat = -1, bestScore = INT_MAX;\n        int secondPat = -1, secondScore = INT_MAX;\n        int thirdPat = -1, thirdScore = INT_MAX;\n        int lastScore = INT_MAX;\n\n        for (int pat = 0; pat < 48; ++pat) {\n            int s = 0;\n            for (int d = 0; d < 4; ++d) s += pattern_penalty(cand[d], pat);\n            if (pat == lastPattern) lastScore = s;\n\n            if (s < bestScore) {\n                thirdScore = secondScore; thirdPat = secondPat;\n                secondScore = bestScore; secondPat = bestPat;\n                bestScore = s; bestPat = pat;\n            } else if (s < secondScore) {\n                thirdScore = secondScore; thirdPat = secondPat;\n                secondScore = s; secondPat = pat;\n            } else if (s < thirdScore) {\n                thirdScore = s; thirdPat = pat;\n            }\n        }\n\n        int n = 0;\n        bool keepLast = (lastPattern != -1 && lastPattern != bestPat && lastScore <= bestScore + 12);\n\n        if (keepLast) active[n++] = lastPattern;\n        active[n++] = bestPat;\n        if (secondPat != -1 && secondPat != bestPat && secondPat != lastPattern) active[n++] = secondPat;\n        else if (thirdPat != -1 && thirdPat != bestPat && thirdPat != lastPattern) active[n++] = thirdPat;\n\n        return n;\n    }\n\n    static inline int softmin2(int a, int b) {\n        if (a > b) swap(a, b);\n        return (3 * a + b) / 4;\n    }\n\n    static inline int softmin3(int a, int b, int c) {\n        if (a > b) swap(a, b);\n        if (b > c) swap(b, c);\n        if (a > b) swap(a, b);\n        return (3 * a + b) / 4;\n    }\n\n    inline void scan_local(const Board &b, const int *active, int nActive,\n                           int &sameAdj, int &diffAdj, int &penalty) const {\n        sameAdj = diffAdj = 0;\n\n        int s0 = 0, s1 = 0, s2 = 0;\n        int pat0 = active[0];\n        int pat1 = (nActive >= 2 ? active[1] : active[0]);\n        int pat2 = (nActive >= 3 ? active[2] : active[0]);\n\n        for (int r = 0; r < 10; ++r) {\n            int base = r * 10;\n            for (int c = 0; c < 10; ++c) {\n                int id = base + c;\n                uint8_t col = b.a[id];\n                if (!col) continue;\n\n                s0 += distCost[pat0][id][col];\n                if (nActive >= 2) s1 += distCost[pat1][id][col];\n                if (nActive >= 3) s2 += distCost[pat2][id][col];\n\n                if (c + 1 < 10 && b.a[id + 1]) {\n                    if (b.a[id + 1] == col) ++sameAdj;\n                    else ++diffAdj;\n                }\n                if (r + 1 < 10 && b.a[id + 10]) {\n                    if (b.a[id + 10] == col) ++sameAdj;\n                    else ++diffAdj;\n                }\n            }\n        }\n\n        if (nActive == 1) penalty = s0;\n        else if (nActive == 2) penalty = softmin2(s0, s1);\n        else penalty = softmin3(s0, s1, s2);\n    }\n\n    long long heuristic_fast(const Board &b, int step, const int *active, int nActive) const {\n        int sameAdj, diffAdj, pen;\n        scan_local(b, active, nActive, sameAdj, diffAdj, pen);\n\n        int rem = 100 - step;\n        long long wPat = 10 + rem / 5;\n\n        return 72LL * sameAdj\n             - 48LL * diffAdj\n             - wPat * pen;\n    }\n\n    long long heuristic_full(const Board &b, int step, const int *active, int nActive) const {\n        int sameAdj, diffAdj, pen;\n        scan_local(b, active, nActive, sameAdj, diffAdj, pen);\n\n        int largest[4] = {};\n        int compCnt[4] = {};\n        int compSq = 0;\n\n        uint8_t vis[100] = {};\n        int q[100];\n\n        for (int s = 0; s < 100; ++s) {\n            uint8_t col = b.a[s];\n            if (!col || vis[s]) continue;\n\n            vis[s] = 1;\n            int head = 0, tail = 0;\n            q[tail++] = s;\n            int sz = 0;\n\n            while (head < tail) {\n                int v = q[head++];\n                ++sz;\n                int r = v / 10, c = v % 10;\n\n                if (r > 0) {\n                    int nv = v - 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (r < 9) {\n                    int nv = v + 10;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c > 0) {\n                    int nv = v - 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n                if (c < 9) {\n                    int nv = v + 1;\n                    if (!vis[nv] && b.a[nv] == col) vis[nv] = 1, q[tail++] = nv;\n                }\n            }\n\n            compSq += sz * sz;\n            largest[col] = max(largest[col], sz);\n            compCnt[col]++;\n        }\n\n        long long optimistic = compSq;\n        long long futureFragPenalty = 0;\n        int curFragments = 0;\n\n        for (int c = 1; c <= 3; ++c) {\n            int remc = suffixCnt[step + 1][c];\n            optimistic += 2LL * largest[c] * remc;\n            futureFragPenalty += 1LL * max(0, compCnt[c] - 1) * remc;\n            curFragments += max(0, compCnt[c] - 1);\n        }\n\n        int rem = 100 - step;\n        long long wPat = 14 + rem / 4;\n\n        return optimistic * 1000LL\n             - futureFragPenalty * 220LL\n             - 95LL * curFragments * curFragments\n             + 50LL * sameAdj\n             - 34LL * diffAdj\n             - wPat * pen;\n    }\n\n    double exact_expect(const Board &state_after_tilt, int step) {\n        int next = step + 1;\n        int empties[100];\n        int m = collect_empties(state_after_tilt, empties);\n\n        if (m == 0) return comp_sq_only(state_after_tilt);\n\n        double sum = 0.0;\n        Board b, tmp;\n\n        for (int i = 0; i < m; ++i) {\n            b = state_after_tilt;\n            b.a[empties[i]] = (uint8_t)flavor[next];\n\n            if (next == 100) {\n                sum += comp_sq_only(b);\n            } else {\n                double best = -1e100;\n                for (int d = 0; d < 4; ++d) {\n                    apply_tilt(b, d, tmp);\n                    best = max(best, exact_expect(tmp, next));\n                }\n                sum += best;\n            }\n        }\n        return sum / m;\n    }\n\n    double one_step_expect(const Board &state_after_tilt, int step, const int *active, int nActive) {\n        int next = step + 1;\n        int empties[100];\n        int m = collect_empties(state_after_tilt, empties);\n\n        if (m == 0) return 0.0;\n\n        double sum = 0.0;\n        Board b, tmp;\n\n        for (int i = 0; i < m; ++i) {\n            b = state_after_tilt;\n            b.a[empties[i]] = (uint8_t)flavor[next];\n\n            if (next == 100) {\n                sum += 3000.0 * comp_sq_only(b);\n            } else {\n                long long best = LLONG_MIN;\n                for (int d = 0; d < 4; ++d) {\n                    apply_tilt(b, d, tmp);\n                    long long v = heuristic_full(tmp, next, active, nActive);\n                    if (v > best) best = v;\n                }\n                sum += (double)best;\n            }\n        }\n\n        return sum / m;\n    }\n\n    int choose_dir(const Board &after_insert, int step) {\n        if (step == 100) return 0;\n\n        Board first[4];\n        for (int d = 0; d < 4; ++d) apply_tilt(after_insert, d, first[d]);\n\n        int active[3];\n        int nActive = select_active_patterns(first, active);\n\n        long long baseH[4];\n        for (int d = 0; d < 4; ++d) baseH[d] = heuristic_full(first[d], step, active, nActive);\n\n        int greedyBest = 0;\n        for (int d = 1; d < 4; ++d) {\n            if (baseH[d] > baseH[greedyBest]) greedyBest = d;\n        }\n\n        auto finalize_pattern = [&](int bestD) {\n            lastPattern = best_pattern_for_board(first[bestD]);\n        };\n\n        if (elapsed() > TIME_LIMIT - 0.03) {\n            finalize_pattern(greedyBest);\n            return greedyBest;\n        }\n\n        int rem = 100 - step;\n\n        // Exact endgame\n        if (rem <= 5 && elapsed() < TIME_LIMIT - 0.03) {\n            double bestVal = -1e100;\n            int bestD = greedyBest;\n            for (int d = 0; d < 4; ++d) {\n                if (elapsed() > TIME_LIMIT - 0.02) break;\n                double v = exact_expect(first[d], step);\n                if (v > bestVal + 1e-12 || (fabs(v - bestVal) <= 1e-12 && baseH[d] > baseH[bestD])) {\n                    bestVal = v;\n                    bestD = d;\n                }\n            }\n            finalize_pattern(bestD);\n            return bestD;\n        }\n\n        // Exact one-step expectation\n        double nextH[4];\n        for (int d = 0; d < 4; ++d) nextH[d] = (double)baseH[d];\n\n        if (elapsed() < TIME_LIMIT - 0.08) {\n            for (int d = 0; d < 4; ++d) {\n                if (elapsed() > TIME_LIMIT - 0.05) break;\n                nextH[d] = one_step_expect(first[d], step, active, nActive);\n            }\n        }\n\n        // Truncated common-random-number rollouts with fast greedy policy\n        long double rollVal[4];\n        for (int d = 0; d < 4; ++d) rollVal[d] = nextH[d];\n\n        int H = 0, K = 0;\n        if (rem > 60) { H = 8; K = 4; }\n        else if (rem > 35) { H = 10; K = 5; }\n        else if (rem > 20) { H = 12; K = 6; }\n        else if (rem > 10) { H = rem; K = 7; }\n        else if (rem > 5) { H = rem; K = 9; }\n\n        double left = TIME_LIMIT - elapsed();\n        if (left < 0.30) K = max(0, K - 2);\n        if (left < 0.18) K = max(0, K - 2);\n        if (left < 0.10) K = 0;\n\n        if (K > 0) {\n            long long sumLeaf[4] = {};\n            int done = 0;\n            int ranks[101];\n            Board sim, tmp, bestBoard;\n\n            int endStep = min(100, step + H);\n\n            for (int it = 0; it < K; ++it) {\n                if (elapsed() > TIME_LIMIT - 0.02) break;\n\n                for (int u = step + 1; u <= endStep; ++u) {\n                    ranks[u] = 1 + rng.next_int(101 - u);\n                }\n\n                for (int d = 0; d < 4; ++d) {\n                    sim = first[d];\n\n                    for (int u = step + 1; u <= endStep; ++u) {\n                        place_by_rank(sim, ranks[u], flavor[u]);\n                        if (u == 100) break;\n\n                        long long bestF = LLONG_MIN;\n                        for (int nd = 0; nd < 4; ++nd) {\n                            apply_tilt(sim, nd, tmp);\n                            long long fv = heuristic_fast(tmp, u, active, nActive);\n                            if (fv > bestF) {\n                                bestF = fv;\n                                bestBoard = tmp;\n                            }\n                        }\n                        sim = bestBoard;\n                    }\n\n                    if (endStep == 100) sumLeaf[d] += 3000LL * comp_sq_only(sim);\n                    else sumLeaf[d] += heuristic_full(sim, endStep, active, nActive);\n                }\n                ++done;\n            }\n\n            if (done > 0) {\n                for (int d = 0; d < 4; ++d) {\n                    rollVal[d] = (long double)sumLeaf[d] / done;\n                }\n            }\n        }\n\n        long double bestScore = -1e300L;\n        int bestD = greedyBest;\n\n        long double wb, wn, wr;\n        if (rem > 40) {\n            wb = 0.15L; wn = 0.60L; wr = 0.25L;\n        } else if (rem > 15) {\n            wb = 0.20L; wn = 0.50L; wr = 0.30L;\n        } else {\n            wb = 0.20L; wn = 0.35L; wr = 0.45L;\n        }\n        if (K == 0) { wb = 0.30L; wn = 0.70L; wr = 0.0L; }\n\n        for (int d = 0; d < 4; ++d) {\n            long double score = wb * (long double)baseH[d]\n                              + wn * (long double)nextH[d]\n                              + wr * rollVal[d];\n            if (score > bestScore + 1e-12L ||\n                (fabsl(score - bestScore) <= 1e-12L && baseH[d] > baseH[bestD])) {\n                bestScore = score;\n                bestD = d;\n            }\n        }\n\n        finalize_pattern(bestD);\n        return bestD;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        for (int i = 1; i <= 100; ++i) {\n            cin >> flavor[i];\n            totalCnt[flavor[i]]++;\n        }\n\n        for (int c = 1; c <= 3; ++c) suffixCnt[101][c] = 0;\n        for (int t = 100; t >= 1; --t) {\n            for (int c = 1; c <= 3; ++c) suffixCnt[t][c] = suffixCnt[t + 1][c];\n            suffixCnt[t][flavor[t]]++;\n        }\n\n        init_patterns();\n\n        uint64_t seed = 0x123456789abcdefULL;\n        for (int i = 1; i <= 100; ++i) {\n            seed = seed * 6364136223846793005ULL + (uint64_t)(flavor[i] + 17);\n        }\n        rng = SplitMix64(seed);\n\n        cur.a.fill(0);\n        st = chrono::steady_clock::now();\n\n        for (int t = 1; t <= 100; ++t) {\n            int p;\n            if (!(cin >> p)) return;\n\n            place_by_rank(cur, p, flavor[t]);\n\n            int d = choose_dir(cur, t);\n\n            Board nxt;\n            apply_tilt(cur, d, nxt);\n            cur = nxt;\n\n            cout << DIR_CH[d] << '\\n' << flush;\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 100;\n\n// ============================================================\n// Utility\n// ============================================================\n\nstatic double expected_score_from_err_rate(double p_err, int N) {\n    p_err = max(0.0, min(1.0, p_err));\n    return pow(0.9, 100.0 * p_err) / N;\n}\nstatic double score_from_counts(int err, int tot, int N) {\n    double p = (err + 0.5) / (tot + 1.0);\n    return expected_score_from_err_rate(p, N);\n}\n\nstatic vector<int> sample_ids_evenly(int M, int S) {\n    S = min(S, M);\n    vector<int> ids;\n    ids.reserve(S);\n    for (int t = 0; t < S; t++) {\n        int id = (long long)t * M / S;\n        if (ids.empty() || ids.back() != id) ids.push_back(id);\n    }\n    if ((int)ids.size() < S) {\n        vector<char> used(M, 0);\n        for (int x : ids) used[x] = 1;\n        for (int i = 0; i < M && (int)ids.size() < S; i++) {\n            if (!used[i]) ids.push_back(i);\n        }\n        sort(ids.begin(), ids.end());\n    }\n    return ids;\n}\n\n// ============================================================\n// Small exact / low-noise family (N <= 6)\n// ============================================================\n\nstruct SmallDB {\n    int N = 0, E = 0, maskCnt = 0, P = 0;\n    vector<pair<int,int>> edges;\n    vector<uint16_t> reps;\n    vector<vector<uint16_t>> repPermMasks;\n    vector<vector<uint8_t>> dist;\n    vector<vector<int>> permMaps;\n};\n\nstatic SmallDB init_small_db(int N) {\n    SmallDB db;\n    db.N = N;\n\n    int edgeIndex[8][8];\n    memset(edgeIndex, -1, sizeof(edgeIndex));\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) {\n            edgeIndex[i][j] = edgeIndex[j][i] = (int)db.edges.size();\n            db.edges.push_back({i, j});\n        }\n    }\n    db.E = (int)db.edges.size();\n    db.maskCnt = 1 << db.E;\n\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n    do {\n        vector<int> mp(db.E);\n        for (int e = 0; e < db.E; e++) {\n            auto [u, v] = db.edges[e];\n            int a = perm[u], b = perm[v];\n            if (a > b) swap(a, b);\n            mp[e] = edgeIndex[a][b];\n        }\n        db.permMaps.push_back(std::move(mp));\n    } while (next_permutation(perm.begin(), perm.end()));\n    db.P = (int)db.permMaps.size();\n\n    vector<uint16_t> permTable((size_t)db.P * db.maskCnt);\n    for (int p = 0; p < db.P; p++) {\n        size_t base = (size_t)p * db.maskCnt;\n        permTable[base] = 0;\n        for (int mask = 1; mask < db.maskCnt; mask++) {\n            int lb = mask & -mask;\n            int bit = __builtin_ctz(lb);\n            int prev = mask ^ lb;\n            permTable[base + mask] = permTable[base + prev] | (uint16_t(1) << db.permMaps[p][bit]);\n        }\n    }\n\n    vector<char> seen(db.maskCnt, 0);\n    for (int mask = 0; mask < db.maskCnt; mask++) {\n        uint16_t best = numeric_limits<uint16_t>::max();\n        for (int p = 0; p < db.P; p++) {\n            uint16_t x = permTable[(size_t)p * db.maskCnt + mask];\n            if (x < best) best = x;\n        }\n        if (!seen[best]) {\n            seen[best] = 1;\n            db.reps.push_back(best);\n        }\n    }\n    sort(db.reps.begin(), db.reps.end());\n\n    int C = (int)db.reps.size();\n    db.repPermMasks.resize(C);\n    for (int i = 0; i < C; i++) {\n        uint16_t rep = db.reps[i];\n        auto& vv = db.repPermMasks[i];\n        vv.reserve(db.P);\n        for (int p = 0; p < db.P; p++) {\n            vv.push_back(permTable[(size_t)p * db.maskCnt + rep]);\n        }\n        sort(vv.begin(), vv.end());\n        vv.erase(unique(vv.begin(), vv.end()), vv.end());\n    }\n\n    db.dist.assign(C, vector<uint8_t>(C, 0));\n    for (int i = 0; i < C; i++) {\n        for (int j = i + 1; j < C; j++) {\n            int best = db.E + 1;\n            for (uint16_t pm : db.repPermMasks[j]) {\n                int d = __builtin_popcount((unsigned)(db.reps[i] ^ pm));\n                if (d < best) best = d;\n                if (best == 0) break;\n            }\n            db.dist[i][j] = db.dist[j][i] = (uint8_t)best;\n        }\n    }\n\n    return db;\n}\n\nstatic uint16_t canonicalize_small(const SmallDB& db, uint16_t mask) {\n    uint16_t best = numeric_limits<uint16_t>::max();\n    for (int p = 0; p < db.P; p++) {\n        uint16_t y = 0;\n        for (int b = 0; b < db.E; b++) {\n            if ((mask >> b) & 1) y |= (uint16_t(1) << db.permMaps[p][b]);\n        }\n        if (y < best) best = y;\n    }\n    return best;\n}\n\nstatic string small_mask_to_string(uint16_t mask, int E) {\n    string s(E, '0');\n    for (int i = 0; i < E; i++) if ((mask >> i) & 1) s[i] = '1';\n    return s;\n}\n\nstatic double small_selection_quality(const SmallDB& db, const vector<int>& sel) {\n    if (sel.size() <= 1) return 0.0;\n    double sum = 0.0;\n    for (int i = 0; i < (int)sel.size(); i++) {\n        int best = 1e9;\n        for (int j = 0; j < (int)sel.size(); j++) if (i != j) {\n            best = min(best, (int)db.dist[sel[i]][sel[j]]);\n        }\n        sum += best;\n    }\n    return sum / sel.size();\n}\n\nstatic vector<int> select_small_code_indices(const SmallDB& db, int M) {\n    int C = (int)db.reps.size();\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        int ea = __builtin_popcount((unsigned)db.reps[a]);\n        int eb = __builtin_popcount((unsigned)db.reps[b]);\n        if (ea != eb) return ea < eb;\n        return db.reps[a] < db.reps[b];\n    });\n\n    if (C <= M) return idx;\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2], idx[C / 3], idx[(2 * C) / 3]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQ = -1.0;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<int> minDist(C, 1e9);\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                minDist[i] = min(minDist[i], (int)db.dist[x][i]);\n            }\n        };\n\n        add_one(seed);\n        while ((int)sel.size() < M) {\n            int nxt = -1, best = -1;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double q = small_selection_quality(db, sel);\n        if (q > bestQ) {\n            bestQ = q;\n            bestSel = sel;\n        }\n    }\n\n    sort(bestSel.begin(), bestSel.end(), [&](int a, int b) {\n        int ea = __builtin_popcount((unsigned)db.reps[a]);\n        int eb = __builtin_popcount((unsigned)db.reps[b]);\n        if (ea != eb) return ea < eb;\n        return db.reps[a] < db.reps[b];\n    });\n    return bestSel;\n}\n\nstruct SmallStrategy {\n    int N = 0, E = 0, M = 0;\n    vector<uint16_t> codeMasks;\n    vector<vector<uint16_t>> codePermMasks;\n    vector<string> graphStrs;\n    double estScore = -1.0;\n};\n\nstatic int decode_small(const SmallStrategy& st, uint16_t mask) {\n    int bestId = 0;\n    int bestDist = st.E + 1;\n    for (int i = 0; i < st.M; i++) {\n        int curBest = st.E + 1;\n        for (uint16_t pm : st.codePermMasks[i]) {\n            int d = __builtin_popcount((unsigned)(mask ^ pm));\n            if (d < curBest) curBest = d;\n            if (curBest == 0) break;\n        }\n        if (curBest < bestDist) {\n            bestDist = curBest;\n            bestId = i;\n        }\n    }\n    return bestId;\n}\n\nstatic double estimate_small_strategy(SmallStrategy& st, double eps, int reps, uint64_t seed) {\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    int err = 0, tot = 0;\n    for (int i = 0; i < st.M; i++) {\n        uint16_t base = st.codeMasks[i];\n        for (int r = 0; r < reps; r++) {\n            uint16_t noisy = base;\n            for (int b = 0; b < st.E; b++) {\n                if (ur(rng) < eps) noisy ^= (uint16_t(1) << b);\n            }\n            int ans = decode_small(st, noisy);\n            if (ans != i) err++;\n            tot++;\n        }\n    }\n    return score_from_counts(err, tot, st.N);\n}\n\n// ============================================================\n// Generic base-candidate representation\n// ============================================================\n\nstruct BaseCand {\n    int B = 0;\n    string baseStr;\n    bool insideClique = false;\n    int edgeBase = 0;\n    int triBase = 0;\n    vector<int> degBaseSorted;\n    vector<int> ndBaseSorted;\n    int familyTag = 0;\n\n    vector<int> degBase;\n    vector<uint32_t> adjMask;\n};\n\nstatic bool cand_less(const BaseCand& a, const BaseCand& b) {\n    if (a.edgeBase != b.edgeBase) return a.edgeBase < b.edgeBase;\n    if (a.insideClique != b.insideClique) return a.insideClique < b.insideClique;\n    if (a.familyTag != b.familyTag) return a.familyTag < b.familyTag;\n    return a.baseStr < b.baseStr;\n}\n\nstatic string build_partition_base_string(const vector<int>& parts, int type) {\n    int B = 0;\n    for (int x : parts) B += x;\n\n    vector<int> block(B);\n    int ptr = 0, bid = 0;\n    for (int x : parts) {\n        for (int i = 0; i < x; i++) block[ptr++] = bid;\n        bid++;\n    }\n\n    string g;\n    g.reserve(B * (B - 1) / 2);\n    for (int i = 0; i < B; i++) {\n        for (int j = i + 1; j < B; j++) {\n            bool same = (block[i] == block[j]);\n            bool e = (type == 0 ? same : !same);\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic string build_threshold_base_string(int B, uint32_t mask) {\n    string g;\n    g.reserve(B * (B - 1) / 2);\n    for (int i = 0; i < B; i++) {\n        for (int j = i + 1; j < B; j++) {\n            bool e = ((mask >> (j - 1)) & 1u) != 0;\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic void analyze_base_candidate(BaseCand& c) {\n    int B = c.B;\n    int deg[MAXN] = {};\n    int nd[MAXN] = {};\n    vector<uint32_t> adjMask(B, 0);\n\n    int pos = 0;\n    for (int i = 0; i < B; i++) {\n        for (int j = i + 1; j < B; j++) {\n            unsigned char bit = (unsigned char)(c.baseStr[pos++] - '0');\n            if (bit) {\n                adjMask[i] |= (1u << j);\n                adjMask[j] |= (1u << i);\n                deg[i]++;\n                deg[j]++;\n                c.edgeBase++;\n            }\n        }\n    }\n\n    for (int i = 0; i < B; i++) {\n        int s = 0;\n        uint32_t m = adjMask[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= (m - 1);\n            s += deg[j];\n        }\n        nd[i] = s;\n    }\n\n    vector<pair<int,int>> feat(B);\n    for (int i = 0; i < B; i++) feat[i] = {deg[i], nd[i]};\n    sort(feat.begin(), feat.end());\n    c.degBaseSorted.resize(B);\n    c.ndBaseSorted.resize(B);\n    for (int i = 0; i < B; i++) {\n        c.degBaseSorted[i] = feat[i].first;\n        c.ndBaseSorted[i] = feat[i].second;\n    }\n\n    c.degBase.assign(deg, deg + B);\n    c.adjMask = std::move(adjMask);\n\n    int tri = 0;\n    for (int i = 0; i < B; i++) {\n        uint32_t mi = c.adjMask[i];\n        while (mi) {\n            int j = __builtin_ctz(mi);\n            mi &= (mi - 1);\n            if (j <= i) continue;\n            uint32_t common = c.adjMask[i] & c.adjMask[j];\n            while (common) {\n                int k = __builtin_ctz(common);\n                common &= (common - 1);\n                if (k > j) tri++;\n            }\n        }\n    }\n    c.triBase = tri;\n}\n\nstatic void gen_partitions_rec(int rem, int last, bool distinctOnly, vector<int>& cur, vector<vector<int>>& out) {\n    if (rem == 0) {\n        out.push_back(cur);\n        return;\n    }\n    for (int x = last; x <= rem; x++) {\n        cur.push_back(x);\n        gen_partitions_rec(rem - x, distinctOnly ? x + 1 : x, distinctOnly, cur, out);\n        cur.pop_back();\n    }\n}\n\nstatic vector<vector<int>> generate_partitions(int B, bool distinctOnly) {\n    vector<vector<int>> out;\n    vector<int> cur;\n    gen_partitions_rec(B, 1, distinctOnly, cur, out);\n    return out;\n}\n\nstatic vector<BaseCand> generate_partition_candidates(int B, bool distinctOnly, int familyTag) {\n    auto plist = generate_partitions(B, distinctOnly);\n    vector<BaseCand> res;\n    unordered_set<string> seen;\n\n    for (const auto& parts : plist) {\n        for (int type = 0; type <= 1; type++) {\n            BaseCand c;\n            c.B = B;\n            c.baseStr = build_partition_base_string(parts, type);\n            c.insideClique = (type == 0);\n            c.familyTag = familyTag;\n            string key;\n            key.reserve(1 + c.baseStr.size());\n            key.push_back(c.insideClique ? '1' : '0');\n            key += c.baseStr;\n            if (!seen.insert(key).second) continue;\n            analyze_base_candidate(c);\n            res.push_back(std::move(c));\n        }\n    }\n\n    sort(res.begin(), res.end(), cand_less);\n    return res;\n}\n\nstatic vector<BaseCand> generate_threshold_candidates(int B, bool insideClique, int familyTag) {\n    vector<BaseCand> res;\n    uint32_t lim = 1u << (B - 1);\n    res.reserve(lim);\n\n    for (uint32_t mask = 0; mask < lim; mask++) {\n        BaseCand c;\n        c.B = B;\n        c.baseStr = build_threshold_base_string(B, mask);\n        c.insideClique = insideClique;\n        c.familyTag = familyTag;\n        analyze_base_candidate(c);\n        res.push_back(std::move(c));\n    }\n\n    sort(res.begin(), res.end(), cand_less);\n    return res;\n}\n\nstatic vector<BaseCand> merge_unique_pools(const vector<vector<BaseCand>>& pools) {\n    vector<BaseCand> res;\n    unordered_set<string> seen;\n    for (const auto& pool : pools) {\n        for (const auto& c : pool) {\n            string key;\n            key.reserve(1 + c.baseStr.size());\n            key.push_back(c.insideClique ? '1' : '0');\n            key += c.baseStr;\n            if (seen.insert(key).second) res.push_back(c);\n        }\n    }\n    sort(res.begin(), res.end(), cand_less);\n    return res;\n}\n\n// ============================================================\n// q+eps-aware block-level selection features\n// ============================================================\n\nstruct SelFeat {\n    vector<float> muDegB;\n    vector<float> muNdB;\n};\n\nstatic SelFeat build_selection_feature(const BaseCand& c, int q, double eps) {\n    int B = c.B;\n    int N = B * q;\n\n    vector<double> muDeg(B), muNd(B);\n    double addInside = c.insideClique ? (q - 1) : 0.0;\n    double shift = eps * (N - 1);\n    double scale = 1.0 - 2.0 * eps;\n\n    for (int i = 0; i < B; i++) {\n        double dclean = 1.0 * q * c.degBase[i] + addInside;\n        muDeg[i] = shift + scale * dclean;\n    }\n\n    double pSame = c.insideClique ? (1.0 - eps) : eps;\n    for (int i = 0; i < B; i++) {\n        double s = (q - 1) * pSame * (1.0 + muDeg[i] - pSame);\n        uint32_t mask = c.adjMask[i];\n        for (int j = 0; j < B; j++) if (j != i) {\n            bool e = ((mask >> j) & 1u) != 0;\n            double p = e ? (1.0 - eps) : eps;\n            s += q * p * (1.0 + muDeg[j] - p);\n        }\n        muNd[i] = s;\n    }\n\n    vector<int> ord(B);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (muDeg[a] != muDeg[b]) return muDeg[a] < muDeg[b];\n        if (muNd[a] != muNd[b]) return muNd[a] < muNd[b];\n        return a < b;\n    });\n\n    SelFeat sf;\n    sf.muDegB.resize(B);\n    sf.muNdB.resize(B);\n    for (int i = 0; i < B; i++) {\n        sf.muDegB[i] = (float)muDeg[ord[i]];\n        sf.muNdB[i] = (float)muNd[ord[i]];\n    }\n    return sf;\n}\n\nstatic vector<SelFeat> build_selection_features_pool(const vector<BaseCand>& pool, int q, double eps) {\n    vector<SelFeat> feats(pool.size());\n    for (int i = 0; i < (int)pool.size(); i++) feats[i] = build_selection_feature(pool[i], q, eps);\n    return feats;\n}\n\nstatic double selection_distance(const SelFeat& a, const SelFeat& b, int q, int N, double eps) {\n    int B = (int)a.muDegB.size();\n    double dDeg = 0.0, dNd = 0.0;\n    for (int i = 0; i < B; i++) {\n        double x = (double)a.muDegB[i] - b.muDegB[i];\n        double y = (double)a.muNdB[i] - b.muNdB[i];\n        dDeg += x * x;\n        dNd += y * y;\n    }\n    dDeg *= q;\n    dNd *= q;\n\n    double alphaNd;\n    if (eps <= 0.10) alphaNd = 0.18;\n    else if (eps <= 0.20) alphaNd = 0.12;\n    else if (eps <= 0.30) alphaNd = 0.08;\n    else alphaNd = 0.05;\n\n    return dDeg + alphaNd * dNd / max(1.0, 1.0 * N * N);\n}\n\nstatic double selection_quality(const vector<SelFeat>& feats, const vector<int>& sel, int q, int N, double eps) {\n    if (sel.size() <= 1) return 0.0;\n    double sum = 0.0;\n    for (int i = 0; i < (int)sel.size(); i++) {\n        double best = 1e100;\n        for (int j = 0; j < (int)sel.size(); j++) if (i != j) {\n            best = min(best, selection_distance(feats[sel[i]], feats[sel[j]], q, N, eps));\n        }\n        sum += best;\n    }\n    return sum / sel.size();\n}\n\nstatic vector<int> select_code_indices_qaware(const vector<BaseCand>& pool, int M, int q, double eps) {\n    int C = (int)pool.size();\n    vector<int> idx(C);\n    iota(idx.begin(), idx.end(), 0);\n\n    if (C <= M) {\n        sort(idx.begin(), idx.end(), [&](int a, int b) { return cand_less(pool[a], pool[b]); });\n        return idx;\n    }\n\n    int B = pool[0].B;\n    int N = B * q;\n    auto feats = build_selection_features_pool(pool, q, eps);\n\n    sort(idx.begin(), idx.end(), [&](int a, int b) {\n        return cand_less(pool[a], pool[b]);\n    });\n\n    vector<int> seeds = {idx.front(), idx.back(), idx[C / 2], idx[C / 3], idx[(2 * C) / 3]};\n    sort(seeds.begin(), seeds.end());\n    seeds.erase(unique(seeds.begin(), seeds.end()), seeds.end());\n\n    vector<int> bestSel;\n    double bestQual = -1.0;\n\n    for (int seed : seeds) {\n        vector<char> used(C, 0);\n        vector<double> minDist(C, 1e100);\n        vector<int> sel;\n        sel.reserve(M);\n\n        auto add_one = [&](int x) {\n            used[x] = 1;\n            sel.push_back(x);\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                double d = selection_distance(feats[x], feats[i], q, N, eps);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        };\n\n        add_one(seed);\n        if (M >= 2) {\n            int far = -1;\n            double best = -1.0;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                double d = selection_distance(feats[seed], feats[i], q, N, eps);\n                if (d > best) {\n                    best = d;\n                    far = i;\n                }\n            }\n            add_one(far);\n        }\n\n        while ((int)sel.size() < M) {\n            int nxt = -1;\n            double best = -1.0;\n            for (int i = 0; i < C; i++) if (!used[i]) {\n                if (minDist[i] > best) {\n                    best = minDist[i];\n                    nxt = i;\n                }\n            }\n            add_one(nxt);\n        }\n\n        double qual = selection_quality(feats, sel, q, N, eps);\n        if (qual > bestQual) {\n            bestQual = qual;\n            bestSel = sel;\n        }\n    }\n\n    sort(bestSel.begin(), bestSel.end(), [&](int a, int b) {\n        return cand_less(pool[a], pool[b]);\n    });\n    return bestSel;\n}\n\nstatic void local_improve_selection(const vector<BaseCand>& pool, vector<int>& sel, int q, double eps) {\n    int C = (int)pool.size();\n    int M = (int)sel.size();\n    if (M <= 2) return;\n\n    int B = pool[0].B;\n    int N = B * q;\n    auto feats = build_selection_features_pool(pool, q, eps);\n\n    auto dist = [&](int a, int b) -> double {\n        return selection_distance(feats[a], feats[b], q, N, eps);\n    };\n\n    vector<char> used(C, 0);\n    for (int x : sel) used[x] = 1;\n\n    const int MAX_ITER = 3;\n    const int WEAK_CNT = min(10, M);\n    const int CAND_CNT = 40;\n\n    for (int it = 0; it < MAX_ITER; it++) {\n        vector<double> best1(M, 1e100), best2(M, 1e100);\n        vector<int> who(M, -1);\n\n        for (int i = 0; i < M; i++) {\n            for (int j = i + 1; j < M; j++) {\n                double d = dist(sel[i], sel[j]);\n                if (d < best1[i]) {\n                    best2[i] = best1[i];\n                    best1[i] = d;\n                    who[i] = j;\n                } else if (d < best2[i]) {\n                    best2[i] = d;\n                }\n                if (d < best1[j]) {\n                    best2[j] = best1[j];\n                    best1[j] = d;\n                    who[j] = i;\n                } else if (d < best2[j]) {\n                    best2[j] = d;\n                }\n            }\n        }\n\n        double curSum = 0.0;\n        vector<int> weakPos(M);\n        iota(weakPos.begin(), weakPos.end(), 0);\n        for (int i = 0; i < M; i++) curSum += best1[i];\n        sort(weakPos.begin(), weakPos.end(), [&](int a, int b) {\n            return best1[a] < best1[b];\n        });\n        weakPos.resize(WEAK_CNT);\n\n        vector<pair<double,int>> cand;\n        cand.reserve(C - M);\n        for (int x = 0; x < C; x++) if (!used[x]) {\n            double md = 1e100;\n            for (int y : sel) md = min(md, dist(x, y));\n            cand.push_back({md, x});\n        }\n        if ((int)cand.size() > CAND_CNT) {\n            nth_element(cand.begin(), cand.begin() + CAND_CNT, cand.end(),\n                        [&](const auto& a, const auto& b) { return a.first > b.first; });\n            cand.resize(CAND_CNT);\n        }\n        sort(cand.begin(), cand.end(), [&](const auto& a, const auto& b) {\n            return a.first > b.first;\n        });\n\n        double bestNewSum = curSum;\n        int bestOutPos = -1;\n        int bestIn = -1;\n\n        for (auto [_, yin] : cand) {\n            vector<double> dy(M);\n            for (int p = 0; p < M; p++) dy[p] = dist(sel[p], yin);\n\n            for (int outPos : weakPos) {\n                double sum = 0.0;\n                double nny = 1e100;\n                for (int p = 0; p < M; p++) if (p != outPos) {\n                    nny = min(nny, dy[p]);\n                    double cur = (who[p] == outPos ? best2[p] : best1[p]);\n                    if (dy[p] < cur) cur = dy[p];\n                    sum += cur;\n                }\n                sum += nny;\n                if (sum > bestNewSum + 1e-12) {\n                    bestNewSum = sum;\n                    bestOutPos = outPos;\n                    bestIn = yin;\n                }\n            }\n        }\n\n        if (bestOutPos == -1) break;\n\n        used[sel[bestOutPos]] = 0;\n        sel[bestOutPos] = bestIn;\n        used[bestIn] = 1;\n    }\n\n    sort(sel.begin(), sel.end(), [&](int a, int b) {\n        return cand_less(pool[a], pool[b]);\n    });\n}\n\nstatic vector<BaseCand> materialize_selected(const vector<BaseCand>& pool, const vector<int>& sel) {\n    vector<BaseCand> ret;\n    ret.reserve(sel.size());\n    for (int id : sel) ret.push_back(pool[id]);\n    sort(ret.begin(), ret.end(), cand_less);\n    return ret;\n}\n\n// ============================================================\n// Generic graph construction from base graph + inside policy\n// ============================================================\n\nstatic string build_full_graph_string(const BaseCand& c, int q) {\n    int B = c.B;\n    int N = B * q;\n\n    string g;\n    g.reserve(N * (N - 1) / 2);\n    for (int i = 0; i < N; i++) {\n        int bi = i / q;\n        for (int j = i + 1; j < N; j++) {\n            int bj = j / q;\n            bool e = (bi == bj ? c.insideClique : ((c.adjMask[bi] >> bj) & 1u));\n            g.push_back(e ? '1' : '0');\n        }\n    }\n    return g;\n}\n\nstatic vector<double> build_proxy_expected_mu(const BaseCand& c, int q, double eps) {\n    int N = c.B * q;\n    double shift = eps * (N - 1);\n    double scale = 1.0 - 2.0 * eps;\n    double add = c.insideClique ? (q - 1) : 0.0;\n\n    vector<double> mu;\n    mu.reserve(N);\n    for (int d0 : c.degBaseSorted) {\n        double d = q * d0 + add;\n        double m = shift + scale * d;\n        for (int t = 0; t < q; t++) mu.push_back(m);\n    }\n    return mu;\n}\n\n// ============================================================\n// Codebook and decoder\n// ============================================================\n\nstruct Codebook {\n    int N = 0, M = 0;\n    double eps = 0.0;\n    double sigma2 = 0.0;\n    vector<string> graphStrs;\n    vector<vector<double>> muDeg;\n    vector<vector<double>> muNd;\n    vector<double> triMu, triVar;\n    double estScore = -1.0;\n};\n\nstatic Codebook build_codebook(const vector<BaseCand>& codes, int q, double eps) {\n    Codebook cb;\n    cb.M = (int)codes.size();\n    cb.N = codes[0].B * q;\n    cb.eps = eps;\n    cb.sigma2 = (cb.N - 1) * eps * (1.0 - eps);\n\n    cb.graphStrs.reserve(cb.M);\n    cb.muDeg.reserve(cb.M);\n    cb.muNd.reserve(cb.M);\n    cb.triMu.reserve(cb.M);\n    cb.triVar.reserve(cb.M);\n\n    static unsigned char adj[MAXN][MAXN];\n    static double p[MAXN][MAXN];\n    int N = cb.N;\n\n    for (const auto& c : codes) {\n        string g = build_full_graph_string(c, q);\n        cb.graphStrs.push_back(g);\n\n        int deg[MAXN] = {};\n        int pos = 0;\n        for (int i = 0; i < N; i++) adj[i][i] = 0;\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                unsigned char bit = (unsigned char)(g[pos++] - '0');\n                adj[i][j] = adj[j][i] = bit;\n                if (bit) {\n                    deg[i]++;\n                    deg[j]++;\n                }\n            }\n        }\n\n        double muDegRaw[MAXN];\n        for (int i = 0; i < N; i++) {\n            muDegRaw[i] = eps * (N - 1) + (1.0 - 2.0 * eps) * deg[i];\n        }\n\n        for (int i = 0; i < N; i++) {\n            p[i][i] = 0.0;\n            for (int j = i + 1; j < N; j++) {\n                double pij = adj[i][j] ? (1.0 - eps) : eps;\n                p[i][j] = p[j][i] = pij;\n            }\n        }\n\n        double muNdRaw[MAXN];\n        for (int i = 0; i < N; i++) {\n            double s = 0.0;\n            for (int j = 0; j < N; j++) if (i != j) {\n                s += p[i][j] * (1.0 + muDegRaw[j] - p[i][j]);\n            }\n            muNdRaw[i] = s;\n        }\n\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (muDegRaw[a] != muDegRaw[b]) return muDegRaw[a] < muDegRaw[b];\n            if (muNdRaw[a] != muNdRaw[b]) return muNdRaw[a] < muNdRaw[b];\n            return a < b;\n        });\n\n        vector<double> md(N), mn(N);\n        for (int i = 0; i < N; i++) {\n            md[i] = muDegRaw[ord[i]];\n            mn[i] = muNdRaw[ord[i]];\n        }\n        cb.muDeg.push_back(std::move(md));\n        cb.muNd.push_back(std::move(mn));\n\n        long long cnt[4] = {};\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                for (int k = j + 1; k < N; k++) {\n                    int e = adj[i][j] + adj[i][k] + adj[j][k];\n                    cnt[e]++;\n                }\n            }\n        }\n\n        double a = 1.0 - eps, b = eps;\n        double triMean = 0.0;\n        triMean += cnt[3] * (a * a * a);\n        triMean += cnt[2] * (a * a * b);\n        triMean += cnt[1] * (a * b * b);\n        triMean += cnt[0] * (b * b * b);\n\n        double total = cnt[0] + cnt[1] + cnt[2] + cnt[3];\n        double pTri = (total > 0 ? triMean / total : 0.0);\n        double triVar = max(1.0, 4.0 * total * pTri * (1.0 - pTri));\n\n        cb.triMu.push_back(triMean);\n        cb.triVar.push_back(triVar);\n    }\n\n    return cb;\n}\n\nstatic int count_triangles(const unsigned char adj[MAXN][MAXN], int N) {\n    int tri = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) if (adj[i][j]) {\n            for (int k = j + 1; k < N; k++) {\n                if (adj[i][k] && adj[j][k]) tri++;\n            }\n        }\n    }\n    return tri;\n}\n\nstatic int decode_codebook(const Codebook& cb, const unsigned char adj[MAXN][MAXN]) {\n    int N = cb.N, M = cb.M;\n\n    int deg[MAXN] = {};\n    int nd[MAXN] = {};\n\n    for (int i = 0; i < N; i++) {\n        for (int j = i + 1; j < N; j++) if (adj[i][j]) {\n            deg[i]++;\n            deg[j]++;\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        int s = 0;\n        for (int j = 0; j < N; j++) if (adj[i][j]) s += deg[j];\n        nd[i] = s;\n    }\n\n    vector<pair<int,int>> obs(N);\n    for (int i = 0; i < N; i++) obs[i] = {deg[i], nd[i]};\n    sort(obs.begin(), obs.end());\n\n    vector<int> obsDeg(N), obsNd(N);\n    for (int i = 0; i < N; i++) {\n        obsDeg[i] = obs[i].first;\n        obsNd[i] = obs[i].second;\n    }\n\n    if (cb.sigma2 < 1e-12) {\n        int bestId = 0;\n        double best = 1e100;\n        for (int k = 0; k < M; k++) {\n            double s = 0.0;\n            const auto& mu = cb.muDeg[k];\n            for (int i = 0; i < N; i++) {\n                double d = obsDeg[i] - mu[i];\n                s += d * d;\n            }\n            if (s < best) {\n                best = s;\n                bestId = k;\n            }\n        }\n        return bestId;\n    }\n\n    vector<double> degSse(M), ndSse(M);\n    double ndDen = max(1.0, cb.sigma2) * 1.0 * N * N * N;\n\n    for (int k = 0; k < M; k++) {\n        double s1 = 0.0, s2 = 0.0;\n        const auto& md = cb.muDeg[k];\n        const auto& mn = cb.muNd[k];\n        for (int i = 0; i < N; i++) {\n            double a = obsDeg[i] - md[i];\n            double b = obsNd[i] - mn[i];\n            s1 += a * a;\n            s2 += b * b;\n        }\n        degSse[k] = s1;\n        ndSse[k] = s2;\n    }\n\n    int triObs = count_triangles(adj, N);\n\n    double betaNd;\n    if (cb.eps <= 0.10) betaNd = 0.32;\n    else if (cb.eps <= 0.20) betaNd = 0.23;\n    else if (cb.eps <= 0.30) betaNd = 0.14;\n    else betaNd = 0.10;\n\n    double betaTri;\n    if (cb.eps <= 0.10) betaTri = 0.18;\n    else if (cb.eps <= 0.20) betaTri = 0.14;\n    else if (cb.eps <= 0.30) betaTri = 0.10;\n    else betaTri = 0.07;\n\n    int ans = 0;\n    double bestScore = 1e100;\n    for (int id = 0; id < M; id++) {\n        double triZ = (triObs - cb.triMu[id]) * (triObs - cb.triMu[id]) / (cb.triVar[id] + 1.0);\n        double score = degSse[id] / (cb.sigma2 + 1e-9)\n                     + betaNd * ndSse[id] / ndDen\n                     + betaTri * triZ;\n        if (score < bestScore) {\n            bestScore = score;\n            ans = id;\n        }\n    }\n    return ans;\n}\n\nstatic double estimate_actual_score(const Codebook& cb, int sampleS, int reps, uint64_t seed) {\n    mt19937_64 rng(seed);\n    uniform_real_distribution<double> ur(0.0, 1.0);\n    auto ids = sample_ids_evenly(cb.M, sampleS);\n\n    static unsigned char adj[MAXN][MAXN];\n    int err = 0, tot = 0;\n\n    for (int id : ids) {\n        const string& g = cb.graphStrs[id];\n        for (int rep = 0; rep < reps; rep++) {\n            int pos = 0;\n            for (int i = 0; i < cb.N; i++) adj[i][i] = 0;\n            for (int i = 0; i < cb.N; i++) {\n                for (int j = i + 1; j < cb.N; j++) {\n                    unsigned char bit = (unsigned char)(g[pos++] - '0');\n                    if (ur(rng) < cb.eps) bit ^= 1;\n                    adj[i][j] = adj[j][i] = bit;\n                }\n            }\n            int ans = decode_codebook(cb, adj);\n            if (ans != id) err++;\n            tot++;\n        }\n    }\n\n    return score_from_counts(err, tot, cb.N);\n}\n\n// ============================================================\n// Proxy search\n// ============================================================\n\nstatic vector<int> q_candidates(int qmax) {\n    vector<int> qs(qmax);\n    iota(qs.begin(), qs.end(), 1);\n    return qs;\n}\n\nstatic double estimate_proxy_score(const vector<BaseCand>& codes, int q, double eps, int reps) {\n    int M = (int)codes.size();\n    int N = codes[0].B * q;\n    double sigma = sqrt(max(0.0, (N - 1) * eps * (1.0 - eps)));\n\n    vector<vector<double>> exps(M);\n    for (int i = 0; i < M; i++) exps[i] = build_proxy_expected_mu(codes[i], q, eps);\n\n    mt19937_64 rng(0x123456789ULL + 10007ULL * codes[0].B + 1000003ULL * q);\n    normal_distribution<double> gauss(0.0, sigma);\n\n    vector<double> noisy(N);\n    int err = 0, tot = 0;\n\n    for (int rep = 0; rep < reps; rep++) {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < N; j++) {\n                double x = exps[i][j];\n                if (sigma > 0) x += gauss(rng);\n                x = max(0.0, min((double)(N - 1), x));\n                noisy[j] = x;\n            }\n            sort(noisy.begin(), noisy.end());\n\n            int bestId = 0;\n            double bestS = 1e100;\n            for (int t = 0; t < M; t++) {\n                double s = 0.0;\n                const auto& mu = exps[t];\n                for (int j = 0; j < N; j++) {\n                    double d = noisy[j] - mu[j];\n                    s += d * d;\n                    if (s >= bestS) break;\n                }\n                if (s < bestS) {\n                    bestS = s;\n                    bestId = t;\n                }\n            }\n            if (bestId != i) err++;\n            tot++;\n        }\n    }\n\n    return score_from_counts(err, tot, N);\n}\n\n// ============================================================\n// Main\n// ============================================================\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int M;\n    double eps;\n    cin >> M >> eps;\n\n    // --------------------------------------------------------\n    // Exact strategy for eps = 0\n    // --------------------------------------------------------\n    if (fabs(eps) < 1e-12) {\n        vector<int> Ns = {4, 5, 6};\n        SmallDB db;\n        int chosenN = -1;\n        for (int N : Ns) {\n            SmallDB cur = init_small_db(N);\n            if ((int)cur.reps.size() >= M) {\n                db = std::move(cur);\n                chosenN = N;\n                break;\n            }\n        }\n        if (chosenN == -1) {\n            db = init_small_db(6);\n            chosenN = 6;\n        }\n\n        vector<uint16_t> chosen(db.reps.begin(), db.reps.begin() + M);\n        unordered_map<int,int> repToIdx;\n        repToIdx.reserve(M * 2);\n        for (int i = 0; i < M; i++) repToIdx[(int)chosen[i]] = i;\n\n        cout << chosenN << '\\n';\n        for (int i = 0; i < M; i++) {\n            cout << small_mask_to_string(chosen[i], db.E) << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; q++) {\n            string H;\n            cin >> H;\n            uint16_t mask = 0;\n            for (int i = 0; i < db.E; i++) if (H[i] == '1') {\n                mask |= (uint16_t(1) << i);\n            }\n            uint16_t canon = canonicalize_small(db, mask);\n            int ans = repToIdx[(int)canon];\n            cout << ans << '\\n';\n            cout.flush();\n        }\n        return 0;\n    }\n\n    // --------------------------------------------------------\n    // Optional low-noise small strategy\n    // --------------------------------------------------------\n    SmallStrategy bestSmall;\n    bool hasSmall = false;\n    if (eps <= 0.03) {\n        vector<int> smallNs;\n        if (M <= 11) smallNs = {4, 5, 6};\n        else if (M <= 34) smallNs = {5, 6};\n        else smallNs = {6};\n\n        for (int N : smallNs) {\n            SmallDB db = init_small_db(N);\n            if ((int)db.reps.size() < M) continue;\n\n            auto sel = select_small_code_indices(db, M);\n\n            SmallStrategy st;\n            st.N = N;\n            st.E = N * (N - 1) / 2;\n            st.M = M;\n            st.codeMasks.reserve(M);\n            st.codePermMasks.reserve(M);\n            st.graphStrs.reserve(M);\n\n            for (int id : sel) {\n                st.codeMasks.push_back(db.reps[id]);\n                st.codePermMasks.push_back(db.repPermMasks[id]);\n                st.graphStrs.push_back(small_mask_to_string(db.reps[id], st.E));\n            }\n\n            st.estScore = estimate_small_strategy(st, eps, 8, 0xABCDEF123456789ULL + 10007ULL * N + M);\n            if (!hasSmall || st.estScore > bestSmall.estScore) {\n                hasSmall = true;\n                bestSmall = std::move(st);\n            }\n        }\n    }\n\n    // --------------------------------------------------------\n    // Build raw candidate pools\n    // --------------------------------------------------------\n    vector<vector<BaseCand>> rawPartAll(24), rawPartDistinct(24);\n    for (int B = 1; B <= 23; B++) {\n        rawPartAll[B] = generate_partition_candidates(B, false, 1);\n        rawPartDistinct[B] = generate_partition_candidates(B, true, 2);\n    }\n\n    vector<vector<BaseCand>> rawThInd(13), rawThCli(13), rawThMix(13), rawAllMix(13);\n    for (int B = 4; B <= 12; B++) {\n        rawThInd[B] = generate_threshold_candidates(B, false, 3);\n        rawThCli[B] = generate_threshold_candidates(B, true, 4);\n        rawThMix[B] = merge_unique_pools({rawThInd[B], rawThCli[B]});\n        rawAllMix[B] = merge_unique_pools({rawPartAll[B], rawThInd[B], rawThCli[B]});\n    }\n\n    struct Book {\n        int B;\n        string tag;\n        vector<BaseCand> pool;\n    };\n    vector<Book> books;\n\n    {\n        int Bmin = -1;\n        for (int B = 1; B <= 23; B++) {\n            if ((int)rawPartAll[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin == -1) Bmin = 23;\n        int Bhi = min(23, Bmin + 7);\n        for (int B = Bmin; B <= Bhi; B++) {\n            if ((int)rawPartAll[B].size() >= M) books.push_back({B, \"part_all\", rawPartAll[B]});\n        }\n    }\n\n    {\n        int Bmin = -1;\n        for (int B = 1; B <= 23; B++) {\n            if ((int)rawPartDistinct[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(23, Bmin + 5);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawPartDistinct[B].size() >= M) books.push_back({B, \"part_distinct\", rawPartDistinct[B]});\n            }\n        }\n    }\n\n    // pure threshold independent blocks\n    {\n        int Bmin = -1;\n        for (int B = 4; B <= 12; B++) {\n            if ((int)rawThInd[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(12, Bmin + 4);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawThInd[B].size() >= M) books.push_back({B, \"th_ind\", rawThInd[B]});\n            }\n        }\n    }\n\n    // pure threshold clique blocks\n    {\n        int Bmin = -1;\n        for (int B = 4; B <= 12; B++) {\n            if ((int)rawThCli[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(12, Bmin + 4);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawThCli[B].size() >= M) books.push_back({B, \"th_cli\", rawThCli[B]});\n            }\n        }\n    }\n\n    // mixed threshold family\n    {\n        int Bmin = -1;\n        for (int B = 4; B <= 12; B++) {\n            if ((int)rawThMix[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(12, Bmin + 4);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawThMix[B].size() >= M) books.push_back({B, \"th_mix\", rawThMix[B]});\n            }\n        }\n    }\n\n    // all mixed family\n    {\n        int Bmin = -1;\n        for (int B = 4; B <= 12; B++) {\n            if ((int)rawAllMix[B].size() >= M) {\n                Bmin = B;\n                break;\n            }\n        }\n        if (Bmin != -1) {\n            int Bhi = min(12, Bmin + 4);\n            for (int B = Bmin; B <= Bhi; B++) {\n                if ((int)rawAllMix[B].size() >= M) books.push_back({B, \"all_mix\", rawAllMix[B]});\n            }\n        }\n    }\n\n    if (books.empty()) {\n        books.push_back({23, \"fallback\", rawPartAll[23]});\n    }\n\n    // --------------------------------------------------------\n    // Proxy search over (book, q)\n    // --------------------------------------------------------\n    struct Combo {\n        double proxy = -1.0;\n        int bookIdx = -1;\n        int q = -1;\n        vector<int> sel;\n    };\n    vector<Combo> combos;\n\n    for (int bi = 0; bi < (int)books.size(); bi++) {\n        int B = books[bi].B;\n        int qmax = 100 / B;\n        auto qs = q_candidates(qmax);\n\n        for (int q : qs) {\n            auto sel = select_code_indices_qaware(books[bi].pool, M, q, eps);\n            auto codes = materialize_selected(books[bi].pool, sel);\n            double pr = estimate_proxy_score(codes, q, eps, 1);\n\n            Combo c;\n            c.proxy = pr;\n            c.bookIdx = bi;\n            c.q = q;\n            c.sel = std::move(sel);\n            combos.push_back(std::move(c));\n        }\n    }\n\n    sort(combos.begin(), combos.end(), [](const Combo& a, const Combo& b) {\n        if (a.proxy != b.proxy) return a.proxy > b.proxy;\n        if (a.bookIdx != b.bookIdx) return a.bookIdx < b.bookIdx;\n        return a.q < b.q;\n    });\n\n    // --------------------------------------------------------\n    // Actual refinement\n    // --------------------------------------------------------\n    struct Refined {\n        Codebook cb;\n        double est = -1.0;\n        int bookIdx = -1;\n        int q = -1;\n    };\n\n    const uint64_t STAGE1_SEED = 0x9E3779B97F4A7C15ULL;\n    const uint64_t STAGE2_SEED = 0xD1B54A32D192ED03ULL;\n    const uint64_t STAGE3_SEED = 0x94D049BB133111EBULL;\n\n    vector<Refined> refined1;\n    int topProxy = min<int>(18, combos.size());\n    for (int i = 0; i < topProxy; i++) {\n        const auto& co = combos[i];\n        auto sel = co.sel;\n        local_improve_selection(books[co.bookIdx].pool, sel, co.q, eps);\n        auto codes = materialize_selected(books[co.bookIdx].pool, sel);\n\n        Codebook cb = build_codebook(codes, co.q, eps);\n        double est = estimate_actual_score(cb, min(M, 26), 1, STAGE1_SEED);\n        cb.estScore = est;\n        refined1.push_back({std::move(cb), est, co.bookIdx, co.q});\n    }\n\n    sort(refined1.begin(), refined1.end(), [](const Refined& a, const Refined& b) {\n        if (a.est != b.est) return a.est > b.est;\n        return a.cb.N < b.cb.N;\n    });\n\n    vector<Refined> refined2;\n    int top1 = min<int>(6, refined1.size());\n    for (int i = 0; i < top1; i++) {\n        auto x = std::move(refined1[i]);\n        x.est = estimate_actual_score(x.cb, min(M, 40), 2, STAGE2_SEED);\n        x.cb.estScore = x.est;\n        refined2.push_back(std::move(x));\n    }\n\n    sort(refined2.begin(), refined2.end(), [](const Refined& a, const Refined& b) {\n        if (a.est != b.est) return a.est > b.est;\n        return a.cb.N < b.cb.N;\n    });\n\n    vector<Refined> refined3;\n    int top2 = min<int>(2, refined2.size());\n    for (int i = 0; i < top2; i++) {\n        auto x = std::move(refined2[i]);\n        x.est = estimate_actual_score(x.cb, min(M, 60), 3, STAGE3_SEED);\n        x.cb.estScore = x.est;\n        refined3.push_back(std::move(x));\n    }\n\n    Codebook bestCB;\n    double bestRobust = -1.0;\n    if (!refined3.empty()) {\n        sort(refined3.begin(), refined3.end(), [](const Refined& a, const Refined& b) {\n            if (a.est != b.est) return a.est > b.est;\n            return a.cb.N < b.cb.N;\n        });\n        bestCB = std::move(refined3[0].cb);\n        bestRobust = refined3[0].est;\n    } else if (!refined2.empty()) {\n        bestCB = std::move(refined2[0].cb);\n        bestRobust = refined2[0].est;\n    } else if (!refined1.empty()) {\n        bestCB = std::move(refined1[0].cb);\n        bestRobust = refined1[0].est;\n    } else {\n        auto sel = select_code_indices_qaware(books[0].pool, M, 1, eps);\n        auto codes = materialize_selected(books[0].pool, sel);\n        bestCB = build_codebook(codes, 1, eps);\n        bestRobust = estimate_actual_score(bestCB, min(M, 20), 1, STAGE1_SEED);\n        bestCB.estScore = bestRobust;\n    }\n\n    bool useSmall = false;\n    if (hasSmall && bestSmall.estScore > bestRobust) {\n        useSmall = true;\n    }\n\n    // --------------------------------------------------------\n    // Output chosen codebook\n    // --------------------------------------------------------\n    int N = useSmall ? bestSmall.N : bestCB.N;\n    cout << N << '\\n';\n    if (useSmall) {\n        for (int i = 0; i < M; i++) cout << bestSmall.graphStrs[i] << '\\n';\n    } else {\n        for (int i = 0; i < M; i++) cout << bestCB.graphStrs[i] << '\\n';\n    }\n    cout.flush();\n\n    // --------------------------------------------------------\n    // Query processing\n    // --------------------------------------------------------\n    if (useSmall) {\n        for (int q = 0; q < 100; q++) {\n            string H;\n            cin >> H;\n            uint16_t mask = 0;\n            for (int i = 0; i < bestSmall.E; i++) {\n                if (H[i] == '1') mask |= (uint16_t(1) << i);\n            }\n            int ans = decode_small(bestSmall, mask);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    } else {\n        static unsigned char adj[MAXN][MAXN];\n        for (int query = 0; query < 100; query++) {\n            string H;\n            cin >> H;\n            int pos = 0;\n            for (int i = 0; i < bestCB.N; i++) adj[i][i] = 0;\n            for (int i = 0; i < bestCB.N; i++) {\n                for (int j = i + 1; j < bestCB.N; j++) {\n                    unsigned char bit = (unsigned char)(H[pos++] - '0');\n                    adj[i][j] = adj[j][i] = bit;\n                }\n            }\n            int ans = decode_codebook(bestCB, adj);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n    }\n\n    return 0;\n}","ahc017":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct RNG {\n    uint64_t x;\n    explicit RNG(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next_u64() {\n        x += 0x9e3779b97f4a7c15ull;\n        uint64_t z = x;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next_u64() % (uint64_t)n);\n    }\n    double next_double() {\n        return (next_u64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    template <class T>\n    void shuffle_vec(vector<T>& a) {\n        for (int i = (int)a.size() - 1; i > 0; --i) {\n            int j = next_int(i + 1);\n            swap(a[i], a[j]);\n        }\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n    double mx, my;\n};\n\nstruct Adj {\n    int to, eid;\n};\n\nstruct PairW {\n    int a, b;\n    double w;\n};\n\nstruct State {\n    vector<int> day;       // size M\n    vector<int> cnt;       // size D\n    vector<double> load;   // normalized importance load per day\n    vector<double> same;   // size M*D, same[e*D+d] = conflict sum if e put on d\n};\n\nclass Solver {\n    static constexpr ll INF = (1LL << 60);\n    static constexpr ll UNREACH = 1000000000LL;\n    static constexpr double PI = 3.14159265358979323846;\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Adj>> g;\n    vector<pair<int,int>> pos;\n    vector<vector<int>> incident;\n    vector<int> degv;\n\n    double centroidX = 0.0, centroidY = 0.0;\n\n    vector<int> sources;\n    int S = 0;\n    vector<vector<ll>> baseDist; // S x N\n\n    vector<double> imp, impN;\n    vector<PairW> conflicts;\n    vector<vector<pair<int,double>>> neigh;\n    vector<double> neighSum;\n    double targetCnt = 0.0;\n    double targetLoad = 0.0;\n\n    chrono::steady_clock::time_point start_time;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - start_time).count();\n    }\n\n    inline double& SAME(State& st, int e, int d) {\n        return st.same[(size_t)e * D + d];\n    }\n    inline double SAMEC(const State& st, int e, int d) const {\n        return st.same[(size_t)e * D + d];\n    }\n\n    void dijkstra_internal(int src, int banDay, const vector<int>& day,\n                           vector<ll>& dist,\n                           vector<int>* parentV = nullptr,\n                           vector<int>* parentE = nullptr) {\n        dist.assign(N, INF);\n        if (parentV) parentV->assign(N, -1);\n        if (parentE) parentE->assign(N, -1);\n\n        priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<pair<ll,int>>> pq;\n        dist[src] = 0;\n        pq.push({0, src});\n\n        while (!pq.empty()) {\n            auto [cd, v] = pq.top();\n            pq.pop();\n            if (cd != dist[v]) continue;\n\n            for (const auto& a : g[v]) {\n                if (banDay >= 0 && day[a.eid] == banDay) continue;\n                int to = a.to;\n                ll nd = cd + edges[a.eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    if (parentV) (*parentV)[to] = v;\n                    if (parentE) (*parentE)[to] = a.eid;\n                    pq.push({nd, to});\n                } else if (parentV && nd == dist[to]) {\n                    if ((*parentE)[to] == -1 || a.eid < (*parentE)[to]) {\n                        (*parentV)[to] = v;\n                        (*parentE)[to] = a.eid;\n                    }\n                }\n            }\n        }\n    }\n\n    void choose_sources() {\n        S = min(12, N);\n\n        // first source near centroid\n        int first = 0;\n        double best = 1e100;\n        for (int i = 0; i < N; ++i) {\n            double dx = pos[i].first - centroidX;\n            double dy = pos[i].second - centroidY;\n            double d2 = dx * dx + dy * dy;\n            if (d2 < best) {\n                best = d2;\n                first = i;\n            }\n        }\n\n        sources.clear();\n        vector<double> minD2(N, 1e100);\n\n        int cur = first;\n        for (int t = 0; t < S; ++t) {\n            sources.push_back(cur);\n            for (int i = 0; i < N; ++i) {\n                double dx = pos[i].first - pos[cur].first;\n                double dy = pos[i].second - pos[cur].second;\n                double d2 = dx * dx + dy * dy;\n                if (d2 < minD2[i]) minD2[i] = d2;\n            }\n            int nxt = -1;\n            double farv = -1.0;\n            for (int i = 0; i < N; ++i) {\n                bool used = false;\n                for (int s : sources) if (s == i) { used = true; break; }\n                if (used) continue;\n                if (minD2[i] > farv) {\n                    farv = minD2[i];\n                    nxt = i;\n                }\n            }\n            if (nxt == -1) break;\n            cur = nxt;\n        }\n        S = (int)sources.size();\n    }\n\n    void compute_importance() {\n        choose_sources();\n        baseDist.assign(S, vector<ll>(N));\n\n        double avgw = 0.0;\n        for (auto& e : edges) avgw += e.w;\n        avgw /= M;\n\n        vector<double> usage(M, 0.0);\n        vector<ll> dist;\n        vector<int> pv, pe;\n\n        vector<int> emptyDay; // banDay < 0 => ignored\n\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, -1, emptyDay, dist, &pv, &pe);\n            baseDist[si] = dist;\n\n            vector<int> ord(N);\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                return dist[a] > dist[b];\n            });\n\n            vector<int> sub(N, 1);\n            for (int v : ord) {\n                if (v == src) continue;\n                if (pe[v] != -1) {\n                    usage[pe[v]] += sub[v];\n                    sub[pv[v]] += sub[v];\n                }\n            }\n        }\n\n        imp.assign(M, 1.0);\n        for (int e = 0; e < M; ++e) {\n            double wf = sqrt((double)edges[e].w / avgw);\n            imp[e] = sqrt(1.0 + usage[e]) * (0.7 + 0.3 * wf);\n        }\n\n        double avgImp = 0.0;\n        for (double x : imp) avgImp += x;\n        avgImp /= M;\n\n        impN.resize(M);\n        for (int e = 0; e < M; ++e) impN[e] = imp[e] / avgImp;\n\n        targetCnt = (double)M / D;\n        double sumImpN = 0.0;\n        for (double x : impN) sumImpN += x;\n        targetLoad = sumImpN / D;\n    }\n\n    void build_conflicts() {\n        struct Tmp {\n            int a, b;\n            double w;\n        };\n        vector<Tmp> tmp;\n        tmp.reserve(200000);\n\n        // strong conflicts for edges sharing a vertex\n        for (int v = 0; v < N; ++v) {\n            auto& inc = incident[v];\n            int deg = (int)inc.size();\n            double lowFactor = 1.0 + 0.8 * max(0, 5 - deg); // deg2 -> strong\n            for (int i = 0; i < deg; ++i) {\n                for (int j = i + 1; j < deg; ++j) {\n                    int a = inc[i], b = inc[j];\n                    if (a > b) swap(a, b);\n                    double w = 40.0 * lowFactor * (0.7 + 0.15 * (impN[a] + impN[b]));\n                    tmp.push_back({a, b, w});\n                }\n            }\n        }\n\n        // medium conflicts for spatially close edges\n        const double R = 110.0;\n        const double R2 = R * R;\n        const int CELL = 110;\n        const int G = 1000 / CELL + 4;\n\n        auto cell_id = [&](int x, int y) {\n            return x * G + y;\n        };\n\n        vector<vector<int>> cells(G * G);\n        for (int e = 0; e < M; ++e) {\n            int cx = min(G - 1, max(0, (int)(edges[e].mx / CELL)));\n            int cy = min(G - 1, max(0, (int)(edges[e].my / CELL)));\n            cells[cell_id(cx, cy)].push_back(e);\n        }\n\n        auto share_vertex = [&](int a, int b) -> bool {\n            const auto& A = edges[a];\n            const auto& B = edges[b];\n            return A.u == B.u || A.u == B.v || A.v == B.u || A.v == B.v;\n        };\n\n        for (int x = 0; x < G; ++x) {\n            for (int y = 0; y < G; ++y) {\n                int id1 = cell_id(x, y);\n                for (int nx = max(0, x - 1); nx <= min(G - 1, x + 1); ++nx) {\n                    for (int ny = max(0, y - 1); ny <= min(G - 1, y + 1); ++ny) {\n                        if (nx < x || (nx == x && ny < y)) continue;\n                        int id2 = cell_id(nx, ny);\n                        const auto& c1 = cells[id1];\n                        const auto& c2 = cells[id2];\n                        if (id1 == id2) {\n                            for (int i = 0; i < (int)c1.size(); ++i) {\n                                for (int j = i + 1; j < (int)c1.size(); ++j) {\n                                    int a = c1[i], b = c1[j];\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        if (a > b) swap(a, b);\n                                        tmp.push_back({a, b, w});\n                                    }\n                                }\n                            }\n                        } else {\n                            for (int a : c1) {\n                                for (int b : c2) {\n                                    if (share_vertex(a, b)) continue;\n                                    double dx = edges[a].mx - edges[b].mx;\n                                    double dy = edges[a].my - edges[b].my;\n                                    double d2 = dx * dx + dy * dy;\n                                    if (d2 <= R2) {\n                                        double prox = 1.0 - d2 / R2;\n                                        double w = 20.0 * prox * prox * (0.6 + 0.2 * (impN[a] + impN[b]));\n                                        int x1 = a, x2 = b;\n                                        if (x1 > x2) swap(x1, x2);\n                                        tmp.push_back({x1, x2, w});\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        sort(tmp.begin(), tmp.end(), [&](const Tmp& p, const Tmp& q) {\n            if (p.a != q.a) return p.a < q.a;\n            return p.b < q.b;\n        });\n\n        conflicts.clear();\n        for (int i = 0; i < (int)tmp.size(); ) {\n            int j = i + 1;\n            double sw = tmp[i].w;\n            while (j < (int)tmp.size() && tmp[j].a == tmp[i].a && tmp[j].b == tmp[i].b) {\n                sw += tmp[j].w;\n                ++j;\n            }\n            conflicts.push_back({tmp[i].a, tmp[i].b, sw});\n            i = j;\n        }\n\n        neigh.assign(M, {});\n        neighSum.assign(M, 0.0);\n        for (auto& p : conflicts) {\n            neigh[p.a].push_back({p.b, p.w});\n            neigh[p.b].push_back({p.a, p.w});\n            neighSum[p.a] += p.w;\n            neighSum[p.b] += p.w;\n        }\n    }\n\n    inline double add_cost(int cnt, double load, double ie, double lc, double li) const {\n        double dc = (cnt + 1 - targetCnt) * (cnt + 1 - targetCnt) - (cnt - targetCnt) * (cnt - targetCnt);\n        double dl = (load + ie - targetLoad) * (load + ie - targetLoad) - (load - targetLoad) * (load - targetLoad);\n        return lc * dc + li * dl;\n    }\n\n    inline double move_delta_proxy(const State& st, int e, int b, double lc, double li) const {\n        int a = st.day[e];\n        if (a == b) return 0.0;\n        if (st.cnt[b] >= K) return 1e100;\n\n        double pairDelta = SAMEC(st, e, b) - SAMEC(st, e, a);\n\n        double dc =\n            (st.cnt[a] - 1 - targetCnt) * (st.cnt[a] - 1 - targetCnt) +\n            (st.cnt[b] + 1 - targetCnt) * (st.cnt[b] + 1 - targetCnt) -\n            (st.cnt[a] - targetCnt) * (st.cnt[a] - targetCnt) -\n            (st.cnt[b] - targetCnt) * (st.cnt[b] - targetCnt);\n\n        double ie = impN[e];\n        double dl =\n            (st.load[a] - ie - targetLoad) * (st.load[a] - ie - targetLoad) +\n            (st.load[b] + ie - targetLoad) * (st.load[b] + ie - targetLoad) -\n            (st.load[a] - targetLoad) * (st.load[a] - targetLoad) -\n            (st.load[b] - targetLoad) * (st.load[b] - targetLoad);\n\n        return pairDelta + lc * dc + li * dl;\n    }\n\n    void apply_move(State& st, int e, int b) {\n        int a = st.day[e];\n        if (a == b) return;\n        st.cnt[a]--;\n        st.cnt[b]++;\n        st.load[a] -= impN[e];\n        st.load[b] += impN[e];\n\n        for (auto [f, w] : neigh[e]) {\n            SAME(st, f, a) -= w;\n            SAME(st, f, b) += w;\n        }\n        st.day[e] = b;\n    }\n\n    State build_state(const vector<int>& day) {\n        State st;\n        st.day = day;\n        st.cnt.assign(D, 0);\n        st.load.assign(D, 0.0);\n\n        for (int e = 0; e < M; ++e) {\n            st.cnt[day[e]]++;\n            st.load[day[e]] += impN[e];\n        }\n\n        st.same.assign((size_t)M * D, 0.0);\n        for (auto& p : conflicts) {\n            SAME(st, p.a, st.day[p.b]) += p.w;\n            SAME(st, p.b, st.day[p.a]) += p.w;\n        }\n        return st;\n    }\n\n    vector<int> construct_initial(int type, RNG& rng, double lc, double li) {\n        vector<int> order;\n        order.reserve(M);\n        vector<int> pref(M, -1);\n\n        if (type == 0) {\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = neighSum[e] + 5.0 * impN[e] + 3.0 * rng.next_double();\n                arr.push_back({-key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n        } else if (type == 1) {\n            double th = rng.next_double() * 2.0 * PI;\n            double cs = cos(th), sn = sin(th);\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double key = edges[e].mx * cs + edges[e].my * sn + 1e-6 * rng.next_double();\n                arr.push_back({key, e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        } else {\n            double shift = rng.next_double() * 2.0 * PI;\n            vector<pair<double,int>> arr;\n            arr.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                double ang = atan2(edges[e].my - centroidY, edges[e].mx - centroidX) - shift;\n                while (ang < 0) ang += 2.0 * PI;\n                while (ang >= 2.0 * PI) ang -= 2.0 * PI;\n                arr.push_back({ang + 1e-6 * rng.next_double(), e});\n            }\n            sort(arr.begin(), arr.end());\n            for (auto& p : arr) order.push_back(p.second);\n            if (rng.next_int(2)) reverse(order.begin(), order.end());\n\n            vector<int> perm(D);\n            iota(perm.begin(), perm.end(), 0);\n            rng.shuffle_vec(perm);\n            for (int i = 0; i < M; ++i) pref[order[i]] = perm[i % D];\n        }\n\n        double prefPenalty = 8.0 + 6.0 * rng.next_double();\n\n        vector<int> day(M, -1);\n        vector<int> cnt(D, 0);\n        vector<double> load(D, 0.0);\n        array<double, 32> tmpConf{};\n\n        for (int e : order) {\n            for (int d = 0; d < D; ++d) tmpConf[d] = 0.0;\n            for (auto [f, w] : neigh[e]) {\n                int df = day[f];\n                if (df != -1) tmpConf[df] += w;\n            }\n\n            int bestd = -1;\n            double bestScore = 1e100;\n            int offset = rng.next_int(D);\n\n            for (int zz = 0; zz < D; ++zz) {\n                int d = (offset + zz) % D;\n                if (cnt[d] >= K) continue;\n                double sc = tmpConf[d] + add_cost(cnt[d], load[d], impN[e], lc, li);\n                if (pref[e] != -1 && d != pref[e]) sc += prefPenalty;\n                sc += 1e-7 * rng.next_double();\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestd = d;\n                }\n            }\n\n            if (bestd == -1) {\n                // fallback, should not happen\n                bestd = 0;\n                while (cnt[bestd] >= K) ++bestd;\n            }\n\n            day[e] = bestd;\n            cnt[bestd]++;\n            load[bestd] += impN[e];\n        }\n\n        return day;\n    }\n\n    void proxy_improve(State& st, RNG& rng, double lc, double li) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < 8; ++pass) {\n            rng.shuffle_vec(ord);\n            int moved = 0;\n\n            for (int e : ord) {\n                int a = st.day[e];\n                int bestd = a;\n                double bestDelta = -1e-9;\n\n                int offset = rng.next_int(D);\n                for (int zz = 0; zz < D; ++zz) {\n                    int d = (offset + zz) % D;\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                    }\n                }\n\n                if (bestd != a) {\n                    apply_move(st, e, bestd);\n                    moved++;\n                }\n            }\n\n            if (moved == 0) break;\n            if (elapsed() > 4.5) break;\n        }\n    }\n\n    ll eval_day_cost(int banDay, const vector<int>& day) {\n        ll res = 0;\n        vector<ll> dist;\n        for (int si = 0; si < S; ++si) {\n            int src = sources[si];\n            dijkstra_internal(src, banDay, day, dist, nullptr, nullptr);\n            const auto& bd = baseDist[si];\n            for (int v = 0; v < N; ++v) {\n                if (v == src) continue;\n                ll nd = (dist[v] >= INF / 2 ? UNREACH : dist[v]);\n                res += nd - bd[v];\n            }\n        }\n        return res;\n    }\n\n    ll eval_schedule(const vector<int>& day, const vector<int>& cnt, vector<ll>& dayCost) {\n        dayCost.assign(D, 0);\n        ll total = 0;\n        for (int d = 0; d < D; ++d) {\n            if (cnt[d] == 0) continue;\n            dayCost[d] = eval_day_cost(d, day);\n            total += dayCost[d];\n        }\n        return total;\n    }\n\n    void actual_refine(vector<int>& bestDay, double lc, double li) {\n        State st = build_state(bestDay);\n        vector<ll> dayCost;\n        ll curScore = eval_schedule(st.day, st.cnt, dayCost);\n\n        int accepted = 0;\n        while (elapsed() < 5.45 && accepted < 25) {\n            vector<int> worstOrd(D);\n            iota(worstOrd.begin(), worstOrd.end(), 0);\n            sort(worstOrd.begin(), worstOrd.end(), [&](int a, int b) {\n                return dayCost[a] > dayCost[b];\n            });\n\n            int takeDays = min(3, D);\n            array<int, 32> isTop{};\n            for (int i = 0; i < takeDays; ++i) isTop[worstOrd[i]] = 1;\n\n            vector<pair<double,int>> candEdges;\n            candEdges.reserve(M);\n            for (int e = 0; e < M; ++e) {\n                int d = st.day[e];\n                if (!isTop[d]) continue;\n                double score = SAMEC(st, e, d) + 4.0 * impN[e];\n                candEdges.push_back({-score, e});\n            }\n\n            if (candEdges.empty()) break;\n            sort(candEdges.begin(), candEdges.end());\n            if ((int)candEdges.size() > 50) candEdges.resize(50);\n\n            vector<int> lowOrd(D);\n            iota(lowOrd.begin(), lowOrd.end(), 0);\n            sort(lowOrd.begin(), lowOrd.end(), [&](int a, int b) {\n                return dayCost[a] < dayCost[b];\n            });\n\n            bool moved = false;\n\n            for (auto [negScore, e] : candEdges) {\n                if (elapsed() > 5.45) break;\n\n                int a = st.day[e];\n                vector<pair<double,int>> pd;\n                pd.reserve(D);\n\n                for (int d = 0; d < D; ++d) {\n                    if (d == a) continue;\n                    if (st.cnt[d] >= K) continue;\n                    double delta = move_delta_proxy(st, e, d, lc, li);\n                    pd.push_back({delta, d});\n                }\n                if (pd.empty()) continue;\n\n                sort(pd.begin(), pd.end());\n                vector<int> candDays;\n                for (int i = 0; i < (int)pd.size() && i < 4; ++i) candDays.push_back(pd[i].second);\n                for (int i = 0; i < min(2, D); ++i) {\n                    int d = lowOrd[i];\n                    if (d == a || st.cnt[d] >= K) continue;\n                    bool found = false;\n                    for (int x : candDays) if (x == d) found = true;\n                    if (!found) candDays.push_back(d);\n                }\n\n                ll bestDelta = 0;\n                int bestd = -1;\n                ll bestA = 0, bestB = 0;\n\n                int old = st.day[e];\n                for (int d : candDays) {\n                    st.day[e] = d;\n                    ll na = eval_day_cost(a, st.day);\n                    ll nb = eval_day_cost(d, st.day);\n                    ll delta = (na + nb) - (dayCost[a] + dayCost[d]);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestd = d;\n                        bestA = na;\n                        bestB = nb;\n                    }\n                }\n                st.day[e] = old;\n\n                if (bestd != -1) {\n                    apply_move(st, e, bestd);\n                    dayCost[a] = bestA;\n                    dayCost[bestd] = bestB;\n                    curScore += bestDelta;\n                    accepted++;\n                    moved = true;\n                    break;\n                }\n            }\n\n            if (!moved) break;\n        }\n\n        bestDay = st.day;\n        (void)curScore;\n    }\n\npublic:\n    void solve() {\n        start_time = chrono::steady_clock::now();\n\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        g.assign(N, {});\n        incident.assign(N, {});\n        degv.assign(N, 0);\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            g[u].push_back({v, i});\n            g[v].push_back({u, i});\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            degv[u]++;\n            degv[v]++;\n        }\n\n        pos.resize(N);\n        for (int i = 0; i < N; ++i) {\n            cin >> pos[i].first >> pos[i].second;\n            centroidX += pos[i].first;\n            centroidY += pos[i].second;\n        }\n        centroidX /= N;\n        centroidY /= N;\n\n        for (int i = 0; i < M; ++i) {\n            edges[i].mx = 0.5 * (pos[edges[i].u].first + pos[edges[i].v].first);\n            edges[i].my = 0.5 * (pos[edges[i].u].second + pos[edges[i].v].second);\n        }\n\n        compute_importance();\n        build_conflicts();\n\n        uint64_t seedBase = 1469598103934665603ull;\n        seedBase ^= (uint64_t)N + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)M + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)D + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n        seedBase ^= (uint64_t)K + 0x9e3779b97f4a7c15ull + (seedBase << 6) + (seedBase >> 2);\n\n        vector<int> bestDay;\n        ll bestScore = (1LL << 62);\n        double bestLc = 4.5, bestLi = 2.0;\n\n        int runs = 0;\n        while (elapsed() < 3.8 && runs < 12) {\n            RNG rng(seedBase + 1000003ull * (uint64_t)runs + 1234567ull);\n\n            double lc = 3.5 + 2.5 * rng.next_double();\n            double li = 1.5 + 2.0 * rng.next_double();\n\n            int type = runs % 3;\n            vector<int> initDay = construct_initial(type, rng, lc, li);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, lc, li);\n\n            vector<ll> dayCost;\n            ll sc = eval_schedule(st.day, st.cnt, dayCost);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestDay = st.day;\n                bestLc = lc;\n                bestLi = li;\n            }\n            runs++;\n        }\n\n        if (bestDay.empty()) {\n            RNG rng(seedBase);\n            vector<int> initDay = construct_initial(0, rng, 4.5, 2.0);\n            State st = build_state(initDay);\n            proxy_improve(st, rng, 4.5, 2.0);\n            bestDay = st.day;\n        }\n\n        actual_refine(bestDay, bestLc, bestLi);\n\n        for (int i = 0; i < M; ++i) {\n            if (i) cout << ' ';\n            cout << bestDay[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\nstatic constexpr int MAXD = 14;\nstatic constexpr int MAXN = MAXD * MAXD * MAXD;\nstatic constexpr int NEG_INF = -1000000000;\n\nint D, Ncells;\n\nstring fstr[2][MAXD], rstr[2][MAXD];\nuint16_t actXMask[2][MAXD], actYMask[2][MAXD];\nvector<int> actXList[2][MAXD], actYList[2][MAXD];\nuint8_t activeCell[2][MAXD][MAXD][MAXD];\n\nchrono::steady_clock::time_point g_start;\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\ninline int idx3(int x, int y, int z) {\n    return x * D * D + y * D + z;\n}\ninline void decode3(int id, int &x, int &y, int &z) {\n    x = id / (D * D);\n    int rem = id % (D * D);\n    y = rem / D;\n    z = rem % D;\n}\ninline int popcnt16(uint16_t x) {\n    return __builtin_popcount((unsigned)x);\n}\n\nuint32_t tiny_hash(uint32_t x) {\n    x ^= x >> 16;\n    x *= 0x7feb352dU;\n    x ^= x >> 15;\n    x *= 0x846ca68bU;\n    x ^= x >> 16;\n    return x;\n}\ninline int tiny_noise(int seed, int x, int y, int z) {\n    uint32_t v = (uint32_t)seed * 1000003u\n               ^ (uint32_t)(x + 1) * 911382323u\n               ^ (uint32_t)(y + 1) * 972663749u\n               ^ (uint32_t)(z + 1) * 19260817u;\n    return (int)(tiny_hash(v) & 31u);\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nstruct AxisInfo {\n    array<int, MAXD + 1> cnt{};\n    long long sumSq = 0;\n    int maxLen = 0;\n    int numSeg = 0;\n};\n\nstruct Comp {\n    vector<int> cells;\n    int vol = 0;\n};\n\nstruct LineSeg {\n    int axis; // 0:x, 1:y, 2:z\n    int x, y, z;\n    int len;\n};\n\nstruct ShapeComp {\n    vector<int> cells;\n    int vol = 0;\n    string sig;\n    array<AxisInfo, 3> ainfo;\n};\n\nstruct LineSegCmp {\n    bool operator()(const LineSeg& a, const LineSeg& b) const {\n        if (a.len != b.len) return a.len < b.len;\n        if (a.axis != b.axis) return a.axis > b.axis;\n        if (a.x != b.x) return a.x > b.x;\n        if (a.y != b.y) return a.y > b.y;\n        return a.z > b.z;\n    }\n};\n\nstruct Candidate {\n    array<uint8_t, MAXN> occ{};\n    vector<ShapeComp> comps;\n};\n\nstruct CoreInfo {\n    vector<char> keep;\n    long double scoreCore = 0.0L;\n    uint16_t covX[MAXD]{};\n    uint16_t covY[MAXD]{};\n    uint16_t coreRow[MAXD][MAXD]{};\n    int remVol[2]{};\n};\n\nstruct Param {\n    int dir;\n    int alpha;\n    int beta;\n    int seed;\n};\n\nstruct PairPlan {\n    long double extraScore = 0.0L;\n    vector<pair<int,int>> matchedExtra;\n    vector<int> compAxis1; // -1 for matched\n    vector<int> compAxis2; // -1 for matched\n};\n\nstruct EvalResult {\n    bool ok = false;\n    long double score = 1e100L;\n    Candidate c1, c2;\n    PairPlan plan;\n};\n\nstruct State {\n    bool ok = false;\n    long double score = 1e100L;\n    CoreInfo core;\n    Candidate c1, c2;\n    PairPlan plan;\n};\n\nvector<Comp> commonComps;\nvector<array<int,3>> rotPerm;\nvector<array<int,3>> rotSign;\n\nint runF[2][MAXD][MAXD][MAXD + 1];\nint runB[2][MAXD][MAXD][MAXD];\n\nint perm_parity(const array<int,3>& p) {\n    int inv = 0;\n    for (int i = 0; i < 3; i++) for (int j = i + 1; j < 3; j++) {\n        if (p[i] > p[j]) inv++;\n    }\n    return (inv % 2 == 0 ? 1 : -1);\n}\n\nvoid init_rotations() {\n    rotPerm.clear();\n    rotSign.clear();\n    array<int,3> p = {0,1,2};\n    sort(p.begin(), p.end());\n    do {\n        int par = perm_parity(p);\n        for (int sx : {-1, 1}) for (int sy : {-1, 1}) for (int sz : {-1, 1}) {\n            if (par * sx * sy * sz == 1) {\n                rotPerm.push_back(p);\n                rotSign.push_back({sx, sy, sz});\n            }\n        }\n    } while (next_permutation(p.begin(), p.end()));\n}\n\nstring canonical_signature(const vector<int>& cells) {\n    vector<array<int,3>> coords;\n    coords.reserve(cells.size());\n    for (int id : cells) {\n        int x, y, z;\n        decode3(id, x, y, z);\n        coords.push_back({x, y, z});\n    }\n\n    string best;\n    bool first = true;\n\n    for (int r = 0; r < (int)rotPerm.size(); r++) {\n        vector<array<int,3>> t;\n        t.reserve(coords.size());\n        int mn0 = INT_MAX, mn1 = INT_MAX, mn2 = INT_MAX;\n\n        const auto& p = rotPerm[r];\n        const auto& s = rotSign[r];\n\n        for (auto &c : coords) {\n            int v[3] = {c[0], c[1], c[2]};\n            int a = s[0] * v[p[0]];\n            int b = s[1] * v[p[1]];\n            int cc = s[2] * v[p[2]];\n            mn0 = min(mn0, a);\n            mn1 = min(mn1, b);\n            mn2 = min(mn2, cc);\n            t.push_back({a, b, cc});\n        }\n\n        for (auto &q : t) {\n            q[0] -= mn0;\n            q[1] -= mn1;\n            q[2] -= mn2;\n        }\n        sort(t.begin(), t.end());\n\n        string sig;\n        sig.reserve(t.size() * 3);\n        for (auto &q : t) {\n            sig.push_back((char)q[0]);\n            sig.push_back((char)q[1]);\n            sig.push_back((char)q[2]);\n        }\n        if (first || sig < best) {\n            best = std::move(sig);\n            first = false;\n        }\n    }\n    return best;\n}\n\nAxisInfo calc_axis_info_from_cells(const vector<int>& cells, int axis) {\n    static array<uint8_t, MAXN> mark;\n    AxisInfo info;\n    int xmin = D, xmax = -1, ymin = D, ymax = -1, zmin = D, zmax = -1;\n\n    for (int id : cells) {\n        mark[id] = 1;\n        int x, y, z;\n        decode3(id, x, y, z);\n        xmin = min(xmin, x); xmax = max(xmax, x);\n        ymin = min(ymin, y); ymax = max(ymax, y);\n        zmin = min(zmin, z); zmax = max(zmax, z);\n    }\n\n    auto add_len = [&](int len) {\n        info.cnt[len]++;\n        info.sumSq += 1LL * len * len;\n        info.maxLen = max(info.maxLen, len);\n        info.numSeg++;\n    };\n\n    if (axis == 0) {\n        for (int y = ymin; y <= ymax; y++) for (int z = zmin; z <= zmax; z++) {\n            int x = xmin;\n            while (x <= xmax) {\n                while (x <= xmax && !mark[idx3(x, y, z)]) x++;\n                if (x > xmax) break;\n                int x0 = x;\n                while (x <= xmax && mark[idx3(x, y, z)]) x++;\n                add_len(x - x0);\n            }\n        }\n    } else if (axis == 1) {\n        for (int x = xmin; x <= xmax; x++) for (int z = zmin; z <= zmax; z++) {\n            int y = ymin;\n            while (y <= ymax) {\n                while (y <= ymax && !mark[idx3(x, y, z)]) y++;\n                if (y > ymax) break;\n                int y0 = y;\n                while (y <= ymax && mark[idx3(x, y, z)]) y++;\n                add_len(y - y0);\n            }\n        }\n    } else {\n        for (int x = xmin; x <= xmax; x++) for (int y = ymin; y <= ymax; y++) {\n            int z = zmin;\n            while (z <= zmax) {\n                while (z <= zmax && !mark[idx3(x, y, z)]) z++;\n                if (z > zmax) break;\n                int z0 = z;\n                while (z <= zmax && mark[idx3(x, y, z)]) z++;\n                add_len(z - z0);\n            }\n        }\n    }\n\n    for (int id : cells) mark[id] = 0;\n    return info;\n}\n\nvoid append_component_axis_segments(const ShapeComp& comp, int axis, vector<LineSeg>& out) {\n    static array<uint8_t, MAXN> mark;\n    int xmin = D, xmax = -1, ymin = D, ymax = -1, zmin = D, zmax = -1;\n    for (int id : comp.cells) {\n        mark[id] = 1;\n        int x, y, z;\n        decode3(id, x, y, z);\n        xmin = min(xmin, x); xmax = max(xmax, x);\n        ymin = min(ymin, y); ymax = max(ymax, y);\n        zmin = min(zmin, z); zmax = max(zmax, z);\n    }\n\n    if (axis == 0) {\n        for (int y = ymin; y <= ymax; y++) for (int z = zmin; z <= zmax; z++) {\n            int x = xmin;\n            while (x <= xmax) {\n                while (x <= xmax && !mark[idx3(x, y, z)]) x++;\n                if (x > xmax) break;\n                int x0 = x;\n                while (x <= xmax && mark[idx3(x, y, z)]) x++;\n                out.push_back({0, x0, y, z, x - x0});\n            }\n        }\n    } else if (axis == 1) {\n        for (int x = xmin; x <= xmax; x++) for (int z = zmin; z <= zmax; z++) {\n            int y = ymin;\n            while (y <= ymax) {\n                while (y <= ymax && !mark[idx3(x, y, z)]) y++;\n                if (y > ymax) break;\n                int y0 = y;\n                while (y <= ymax && mark[idx3(x, y, z)]) y++;\n                out.push_back({1, x, y0, z, y - y0});\n            }\n        }\n    } else {\n        for (int x = xmin; x <= xmax; x++) for (int y = ymin; y <= ymax; y++) {\n            int z = zmin;\n            while (z <= zmax) {\n                while (z <= zmax && !mark[idx3(x, y, z)]) z++;\n                if (z > zmax) break;\n                int z0 = z;\n                while (z <= zmax && mark[idx3(x, y, z)]) z++;\n                out.push_back({2, x, y, z0, z - z0});\n            }\n        }\n    }\n\n    for (int id : comp.cells) mark[id] = 0;\n}\n\nvoid extract_shape_components(const array<uint8_t, MAXN>& occ, vector<ShapeComp>& out) {\n    out.clear();\n    vector<uint8_t> vis(Ncells, 0);\n    const int dx[6] = {1, -1, 0, 0, 0, 0};\n    const int dy[6] = {0, 0, 1, -1, 0, 0};\n    const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    for (int s = 0; s < Ncells; s++) {\n        if (!occ[s] || vis[s]) continue;\n        queue<int> q;\n        q.push(s);\n        vis[s] = 1;\n        ShapeComp c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (occ[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        c.sig = canonical_signature(c.cells);\n        for (int a = 0; a < 3; a++) c.ainfo[a] = calc_axis_info_from_cells(c.cells, a);\n        out.push_back(std::move(c));\n    }\n}\n\nvoid build_full_common_components() {\n    vector<uint8_t> common(Ncells, 0);\n    for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) for (int z = 0; z < D; z++) {\n        if (activeCell[0][x][y][z] && activeCell[1][x][y][z]) {\n            common[idx3(x, y, z)] = 1;\n        }\n    }\n\n    vector<uint8_t> vis(Ncells, 0);\n    const int dx[6] = {1, -1, 0, 0, 0, 0};\n    const int dy[6] = {0, 0, 1, -1, 0, 0};\n    const int dz[6] = {0, 0, 0, 0, 1, -1};\n\n    for (int s = 0; s < Ncells; s++) {\n        if (!common[s] || vis[s]) continue;\n        queue<int> q;\n        q.push(s);\n        vis[s] = 1;\n        Comp c;\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            c.cells.push_back(v);\n            int x, y, z;\n            decode3(v, x, y, z);\n            for (int dir = 0; dir < 6; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir], nz = z + dz[dir];\n                if (nx < 0 || nx >= D || ny < 0 || ny >= D || nz < 0 || nz >= D) continue;\n                int nid = idx3(nx, ny, nz);\n                if (common[nid] && !vis[nid]) {\n                    vis[nid] = 1;\n                    q.push(nid);\n                }\n            }\n        }\n        c.vol = (int)c.cells.size();\n        commonComps.push_back(std::move(c));\n    }\n}\n\nCoreInfo build_core_from_keep(const vector<char>& keep) {\n    CoreInfo core;\n    core.keep = keep;\n    for (int z = 0; z < D; z++) {\n        core.covX[z] = 0;\n        core.covY[z] = 0;\n        for (int x = 0; x < D; x++) core.coreRow[z][x] = 0;\n    }\n\n    for (int cid = 0; cid < (int)commonComps.size(); cid++) {\n        if (!keep[cid]) continue;\n        core.scoreCore += 1.0L / (long double)commonComps[cid].vol;\n        for (int id : commonComps[cid].cells) {\n            int x, y, z;\n            decode3(id, x, y, z);\n            core.covX[z] |= (uint16_t(1) << x);\n            core.covY[z] |= (uint16_t(1) << y);\n            core.coreRow[z][x] |= (uint16_t(1) << y);\n        }\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        int vol = 0;\n        for (int z = 0; z < D; z++) {\n            int ur = popcnt16(actXMask[obj][z] & ~core.covX[z]);\n            int uc = popcnt16(actYMask[obj][z] & ~core.covY[z]);\n            vol += max(ur, uc);\n        }\n        core.remVol[obj] = vol;\n    }\n    return core;\n}\n\nCoreInfo build_core_by_threshold(int threshold) {\n    vector<char> keep(commonComps.size(), 0);\n    for (int i = 0; i < (int)commonComps.size(); i++) {\n        if (commonComps[i].vol > threshold) keep[i] = 1;\n    }\n    return build_core_from_keep(keep);\n}\n\nvoid build_runs(const CoreInfo& core) {\n    for (int obj = 0; obj < 2; obj++) {\n        for (int x = 0; x < D; x++) {\n            for (int y = 0; y < D; y++) {\n                runF[obj][x][y][D] = 0;\n                for (int z = D - 1; z >= 0; z--) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runF[obj][x][y][z] = avail ? 1 + runF[obj][x][y][z + 1] : 0;\n                }\n                for (int z = 0; z < D; z++) {\n                    bool avail = activeCell[obj][x][y][z] && (((core.coreRow[z][x] >> y) & 1) == 0);\n                    runB[obj][x][y][z] = avail ? 1 + (z ? runB[obj][x][y][z - 1] : 0) : 0;\n                }\n            }\n        }\n    }\n}\n\nvector<int> solve_dp_assignment(\n    const vector<int>& domain,\n    const vector<int>& choices,\n    const vector<int>& mandatory,\n    int w[MAXD][MAXD]\n) {\n    int p = (int)domain.size();\n    int q = (int)choices.size();\n    int m = (int)mandatory.size();\n\n    vector<int> ret(p, 0);\n    if (p == 0) return ret;\n\n    int pos[MAXD];\n    for (int i = 0; i < MAXD; i++) pos[i] = -1;\n    for (int i = 0; i < m; i++) pos[mandatory[i]] = i;\n\n    int bitOfChoice[MAXD];\n    for (int j = 0; j < q; j++) {\n        bitOfChoice[j] = (pos[choices[j]] == -1 ? 0 : (1 << pos[choices[j]]));\n    }\n\n    int S = 1 << m;\n    static int dp[1 << MAXD], ndp[1 << MAXD];\n    static uint16_t parentMask[MAXD + 1][1 << MAXD];\n    static int8_t parentChoice[MAXD + 1][1 << MAXD];\n\n    for (int mask = 0; mask < S; mask++) dp[mask] = NEG_INF;\n    dp[0] = 0;\n\n    for (int i = 0; i < p; i++) {\n        for (int mask = 0; mask < S; mask++) ndp[mask] = NEG_INF;\n        for (int mask = 0; mask < S; mask++) if (dp[mask] > NEG_INF / 2) {\n            for (int j = 0; j < q; j++) {\n                int ww = w[i][j];\n                if (ww <= NEG_INF / 2) continue;\n                int nmask = mask | bitOfChoice[j];\n                int val = dp[mask] + ww;\n                if (val > ndp[nmask]) {\n                    ndp[nmask] = val;\n                    parentMask[i + 1][nmask] = (uint16_t)mask;\n                    parentChoice[i + 1][nmask] = (int8_t)j;\n                }\n            }\n        }\n        for (int mask = 0; mask < S; mask++) dp[mask] = ndp[mask];\n    }\n\n    int full = S - 1;\n    if (dp[full] <= NEG_INF / 2) {\n        for (int i = 0; i < p; i++) {\n            int bestj = 0, bestv = NEG_INF;\n            for (int j = 0; j < q; j++) {\n                if (w[i][j] > bestv) {\n                    bestv = w[i][j];\n                    bestj = j;\n                }\n            }\n            ret[i] = bestj;\n        }\n        return ret;\n    }\n\n    int mask = full;\n    for (int i = p; i >= 1; i--) {\n        int j = parentChoice[i][mask];\n        ret[i - 1] = j;\n        mask = parentMask[i][mask];\n    }\n    return ret;\n}\n\nCandidate build_candidate_dp(\n    int obj,\n    const CoreInfo& core,\n    const Param& prm,\n    const array<uint8_t, MAXN>* prefOcc = nullptr,\n    int overlapBonus = 0\n) {\n    Candidate cand;\n    cand.occ.fill(0);\n\n    uint16_t prevRow[MAXD]{};\n    uint16_t curRow[MAXD]{};\n\n    int zStart = (prm.dir == 1 ? 0 : D - 1);\n    int zEnd   = (prm.dir == 1 ? D : -1);\n    int zStep  = (prm.dir == 1 ? 1 : -1);\n\n    for (int z = zStart; z != zEnd; z += zStep) {\n        for (int x = 0; x < D; x++) curRow[x] = 0;\n\n        vector<int> uncRows, uncCols;\n        uint16_t rowMask = actXMask[obj][z] & ~core.covX[z];\n        uint16_t colMask = actYMask[obj][z] & ~core.covY[z];\n\n        for (int x : actXList[obj][z]) if ((rowMask >> x) & 1) uncRows.push_back(x);\n        for (int y : actYList[obj][z]) if ((colMask >> y) & 1) uncCols.push_back(y);\n\n        if (uncRows.empty() && uncCols.empty()) {\n            memcpy(prevRow, curRow, sizeof(prevRow));\n            continue;\n        }\n\n        int w[MAXD][MAXD];\n        for (int i = 0; i < MAXD; i++) for (int j = 0; j < MAXD; j++) w[i][j] = NEG_INF;\n\n        if ((int)uncRows.size() >= (int)uncCols.size()) {\n            const auto& domain = uncRows;\n            const auto& choices = actYList[obj][z];\n            const auto& mandatory = uncCols;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int y = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue;\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int ov = (prefOcc && (*prefOcc)[idx3(x, y, z)]) ? overlapBonus : 0;\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + ov + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int x = domain[i];\n                int y = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        } else {\n            const auto& domain = uncCols;\n            const auto& choices = actXList[obj][z];\n            const auto& mandatory = uncRows;\n\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                for (int j = 0; j < (int)choices.size(); j++) {\n                    int x = choices[j];\n                    if ((core.coreRow[z][x] >> y) & 1) continue;\n                    int cont = ((prevRow[x] >> y) & 1) ? prm.alpha : 0;\n                    int rr = (prm.dir == 1 ? runF[obj][x][y][z] : runB[obj][x][y][z]);\n                    int fut = prm.beta * max(0, rr - 1);\n                    int ov = (prefOcc && (*prefOcc)[idx3(x, y, z)]) ? overlapBonus : 0;\n                    int noi = tiny_noise(prm.seed, x, y, z);\n                    w[i][j] = cont + fut + ov + noi;\n                }\n            }\n\n            vector<int> asg = solve_dp_assignment(domain, choices, mandatory, w);\n            for (int i = 0; i < (int)domain.size(); i++) {\n                int y = domain[i];\n                int x = choices[asg[i]];\n                curRow[x] |= (uint16_t(1) << y);\n                cand.occ[idx3(x, y, z)] = 1;\n            }\n        }\n\n        memcpy(prevRow, curRow, sizeof(prevRow));\n    }\n\n    extract_shape_components(cand.occ, cand.comps);\n    return cand;\n}\n\nCandidate build_candidate_group_shift(int obj, const CoreInfo& core, bool revA, bool revB, int shift) {\n    Candidate cand;\n    cand.occ.fill(0);\n\n    for (int z = 0; z < D; z++) {\n        vector<int> uncRows, uncCols;\n        uint16_t rowMask = actXMask[obj][z] & ~core.covX[z];\n        uint16_t colMask = actYMask[obj][z] & ~core.covY[z];\n\n        for (int x : actXList[obj][z]) if ((rowMask >> x) & 1) uncRows.push_back(x);\n        for (int y : actYList[obj][z]) if ((colMask >> y) & 1) uncCols.push_back(y);\n\n        if (uncRows.empty() && uncCols.empty()) continue;\n\n        if ((int)uncRows.size() >= (int)uncCols.size()) {\n            vector<int> X = uncRows;\n            vector<int> Yreq = uncCols;\n            const auto& Yall = actYList[obj][z];\n\n            if (revA) reverse(X.begin(), X.end());\n            if (revB) reverse(Yreq.begin(), Yreq.end());\n            if (!Yreq.empty()) {\n                int s = shift % (int)Yreq.size();\n                rotate(Yreq.begin(), Yreq.begin() + s, Yreq.end());\n            }\n\n            if (Yreq.empty()) {\n                int y = Yall[shift % (int)Yall.size()];\n                for (int x : X) cand.occ[idx3(x, y, z)] = 1;\n            } else {\n                int p = (int)X.size(), k = (int)Yreq.size();\n                for (int g = 0; g < k; g++) {\n                    int l = (long long)g * p / k;\n                    int r = (long long)(g + 1) * p / k;\n                    int y = Yreq[g];\n                    for (int i = l; i < r; i++) cand.occ[idx3(X[i], y, z)] = 1;\n                }\n            }\n        } else {\n            vector<int> Y = uncCols;\n            vector<int> Xreq = uncRows;\n            const auto& Xall = actXList[obj][z];\n\n            if (revA) reverse(Y.begin(), Y.end());\n            if (revB) reverse(Xreq.begin(), Xreq.end());\n            if (!Xreq.empty()) {\n                int s = shift % (int)Xreq.size();\n                rotate(Xreq.begin(), Xreq.begin() + s, Xreq.end());\n            }\n\n            if (Xreq.empty()) {\n                int x = Xall[shift % (int)Xall.size()];\n                for (int y : Y) cand.occ[idx3(x, y, z)] = 1;\n            } else {\n                int p = (int)Y.size(), k = (int)Xreq.size();\n                for (int g = 0; g < k; g++) {\n                    int l = (long long)g * p / k;\n                    int r = (long long)(g + 1) * p / k;\n                    int x = Xreq[g];\n                    for (int i = l; i < r; i++) cand.occ[idx3(x, Y[i], z)] = 1;\n                }\n            }\n        }\n    }\n\n    extract_shape_components(cand.occ, cand.comps);\n    return cand;\n}\n\nlong double score_from_counts(array<int, MAXD + 1> a, array<int, MAXD + 1> b) {\n    long double sc = 0.0L;\n    while (true) {\n        int i = 0, j = 0;\n        for (int t = D; t >= 1; t--) if (a[t] > 0) { i = t; break; }\n        for (int t = D; t >= 1; t--) if (b[t] > 0) { j = t; break; }\n        if (i == 0 || j == 0) break;\n        int c = min(a[i], b[j]);\n        int m = min(i, j);\n        sc += (long double)c / (long double)m;\n        a[i] -= c;\n        b[j] -= c;\n        if (i > j) a[i - j] += c;\n        else if (j > i) b[j - i] += c;\n    }\n    long long ex = 0;\n    for (int t = 1; t <= D; t++) {\n        ex += 1LL * t * a[t];\n        ex += 1LL * t * b[t];\n    }\n    sc += (long double)ex;\n    return sc;\n}\n\nvoid add_counts(array<int, MAXD + 1>& dst, const array<int, MAXD + 1>& src, int sign) {\n    for (int t = 1; t <= D; t++) dst[t] += sign * src[t];\n}\n\nPairPlan make_pair_plan(const Candidate& c1, const Candidate& c2) {\n    PairPlan plan;\n\n    unordered_map<string, vector<int>> mp1, mp2;\n    mp1.reserve(c1.comps.size() * 2 + 1);\n    mp2.reserve(c2.comps.size() * 2 + 1);\n\n    for (int i = 0; i < (int)c1.comps.size(); i++) mp1[c1.comps[i].sig].push_back(i);\n    for (int i = 0; i < (int)c2.comps.size(); i++) mp2[c2.comps[i].sig].push_back(i);\n\n    vector<char> used1(c1.comps.size(), 0), used2(c2.comps.size(), 0);\n\n    for (auto &kv : mp1) {\n        auto it = mp2.find(kv.first);\n        if (it == mp2.end()) continue;\n        int cnt = min((int)kv.second.size(), (int)it->second.size());\n        for (int t = 0; t < cnt; t++) {\n            int i = kv.second[t];\n            int j = it->second[t];\n            used1[i] = 1;\n            used2[j] = 1;\n            plan.matchedExtra.push_back({i, j});\n            plan.extraScore += 1.0L / (long double)c1.comps[i].vol;\n        }\n    }\n\n    vector<int> ids1, ids2;\n    for (int i = 0; i < (int)c1.comps.size(); i++) if (!used1[i]) ids1.push_back(i);\n    for (int i = 0; i < (int)c2.comps.size(); i++) if (!used2[i]) ids2.push_back(i);\n\n    auto better_heu = [&](const AxisInfo& a, const AxisInfo& b) {\n        if (a.sumSq != b.sumSq) return a.sumSq > b.sumSq;\n        if (a.maxLen != b.maxLen) return a.maxLen > b.maxLen;\n        return a.numSeg < b.numSeg;\n    };\n\n    vector<int> bestHeu1(ids1.size(), 0), bestHeu2(ids2.size(), 0);\n    for (int k = 0; k < (int)ids1.size(); k++) {\n        int best = 0;\n        for (int a = 1; a < 3; a++) if (better_heu(c1.comps[ids1[k]].ainfo[a], c1.comps[ids1[k]].ainfo[best])) best = a;\n        bestHeu1[k] = best;\n    }\n    for (int k = 0; k < (int)ids2.size(); k++) {\n        int best = 0;\n        for (int a = 1; a < 3; a++) if (better_heu(c2.comps[ids2[k]].ainfo[a], c2.comps[ids2[k]].ainfo[best])) best = a;\n        bestHeu2[k] = best;\n    }\n\n    auto build_counts1 = [&](const vector<int>& sel) {\n        array<int, MAXD + 1> tot{};\n        for (int k = 0; k < (int)sel.size(); k++) add_counts(tot, c1.comps[ids1[k]].ainfo[sel[k]].cnt, +1);\n        return tot;\n    };\n    auto build_counts2 = [&](const vector<int>& sel) {\n        array<int, MAXD + 1> tot{};\n        for (int k = 0; k < (int)sel.size(); k++) add_counts(tot, c2.comps[ids2[k]].ainfo[sel[k]].cnt, +1);\n        return tot;\n    };\n\n    long double bestRes = 1e100L;\n    vector<int> bestSel1, bestSel2;\n\n    auto try_start = [&](const vector<int>& s1, const vector<int>& s2) {\n        auto cA = build_counts1(s1);\n        auto cB = build_counts2(s2);\n        long double sc = score_from_counts(cA, cB);\n        if (sc < bestRes) {\n            bestRes = sc;\n            bestSel1 = s1;\n            bestSel2 = s2;\n        }\n    };\n\n    for (int a1 = 0; a1 < 3; a1++) {\n        vector<int> s1(ids1.size(), a1);\n        for (int a2 = 0; a2 < 3; a2++) {\n            vector<int> s2(ids2.size(), a2);\n            try_start(s1, s2);\n        }\n    }\n    {\n        vector<int> s1 = bestHeu1;\n        for (int a2 = 0; a2 < 3; a2++) {\n            vector<int> s2(ids2.size(), a2);\n            try_start(s1, s2);\n        }\n    }\n    {\n        vector<int> s2 = bestHeu2;\n        for (int a1 = 0; a1 < 3; a1++) {\n            vector<int> s1(ids1.size(), a1);\n            try_start(s1, s2);\n        }\n    }\n    try_start(bestHeu1, bestHeu2);\n\n    vector<int> cur1 = bestSel1, cur2 = bestSel2;\n    auto cnt1 = build_counts1(cur1);\n    auto cnt2 = build_counts2(cur2);\n    long double curScore = bestRes;\n\n    for (int pass = 0; pass < 3; pass++) {\n        bool improved = false;\n\n        for (int k = 0; k < (int)cur1.size(); k++) {\n            int olda = cur1[k];\n            int besta = olda;\n            long double bestLocal = curScore;\n            for (int a = 0; a < 3; a++) if (a != olda) {\n                auto tmp = cnt1;\n                add_counts(tmp, c1.comps[ids1[k]].ainfo[olda].cnt, -1);\n                add_counts(tmp, c1.comps[ids1[k]].ainfo[a].cnt, +1);\n                long double sc = score_from_counts(tmp, cnt2);\n                if (sc + 1e-15L < bestLocal) {\n                    bestLocal = sc;\n                    besta = a;\n                }\n            }\n            if (besta != olda) {\n                add_counts(cnt1, c1.comps[ids1[k]].ainfo[olda].cnt, -1);\n                add_counts(cnt1, c1.comps[ids1[k]].ainfo[besta].cnt, +1);\n                cur1[k] = besta;\n                curScore = bestLocal;\n                improved = true;\n            }\n        }\n\n        for (int k = 0; k < (int)cur2.size(); k++) {\n            int olda = cur2[k];\n            int besta = olda;\n            long double bestLocal = curScore;\n            for (int a = 0; a < 3; a++) if (a != olda) {\n                auto tmp = cnt2;\n                add_counts(tmp, c2.comps[ids2[k]].ainfo[olda].cnt, -1);\n                add_counts(tmp, c2.comps[ids2[k]].ainfo[a].cnt, +1);\n                long double sc = score_from_counts(cnt1, tmp);\n                if (sc + 1e-15L < bestLocal) {\n                    bestLocal = sc;\n                    besta = a;\n                }\n            }\n            if (besta != olda) {\n                add_counts(cnt2, c2.comps[ids2[k]].ainfo[olda].cnt, -1);\n                add_counts(cnt2, c2.comps[ids2[k]].ainfo[besta].cnt, +1);\n                cur2[k] = besta;\n                curScore = bestLocal;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    plan.compAxis1.assign(c1.comps.size(), -1);\n    plan.compAxis2.assign(c2.comps.size(), -1);\n    for (int k = 0; k < (int)ids1.size(); k++) plan.compAxis1[ids1[k]] = cur1[k];\n    for (int k = 0; k < (int)ids2.size(); k++) plan.compAxis2[ids2[k]] = cur2[k];\n\n    plan.extraScore += curScore;\n    return plan;\n}\n\nvector<int> select_thresholds() {\n    vector<int> u;\n    for (auto &c : commonComps) u.push_back(c.vol);\n    sort(u.begin(), u.end());\n    u.erase(unique(u.begin(), u.end()), u.end());\n\n    vector<int> th;\n    auto add = [&](int v) {\n        if (find(th.begin(), th.end(), v) == th.end()) th.push_back(v);\n    };\n\n    add(-1);\n    if (u.empty()) {\n        sort(th.begin(), th.end());\n        return th;\n    }\n\n    int m = (int)u.size();\n    for (int i = 0; i < min(m, 6); i++) add(u[i] - 1);\n    add(u[m / 4] - 1);\n    add(u[m / 2] - 1);\n    add(u[(3 * m) / 4] - 1);\n    add(u.back() - 1);\n    add(u.back());\n\n    sort(th.begin(), th.end());\n    th.erase(unique(th.begin(), th.end()), th.end());\n    return th;\n}\n\nstring occ_key(const array<uint8_t, MAXN>& occ) {\n    return string(reinterpret_cast<const char*>(occ.data()), Ncells);\n}\n\nbool same_core(const State& a, const State& b) {\n    return a.core.keep == b.core.keep;\n}\n\nbool same_state(const State& a, const State& b) {\n    if (!same_core(a, b)) return false;\n    if (a.c1.occ != b.c1.occ) return false;\n    if (a.c2.occ != b.c2.occ) return false;\n    return true;\n}\n\nState make_state(const CoreInfo& core, const EvalResult& ev) {\n    State s;\n    s.ok = ev.ok;\n    s.score = ev.score;\n    s.core = core;\n    s.c1 = ev.c1;\n    s.c2 = ev.c2;\n    s.plan = ev.plan;\n    return s;\n}\n\nvoid insert_elite(vector<State>& elites, const State& s, int K) {\n    if (!s.ok) return;\n    for (const auto& e : elites) {\n        if (same_state(e, s)) return;\n    }\n    elites.push_back(s);\n    sort(elites.begin(), elites.end(), [](const State& a, const State& b) {\n        return a.score < b.score;\n    });\n    if ((int)elites.size() > K) elites.resize(K);\n}\n\nEvalResult evaluate_core(const CoreInfo& core, const vector<Param>& dpParams, double timeLimit) {\n    EvalResult res;\n    build_runs(core);\n\n    vector<Candidate> cand[2];\n\n    for (int obj = 0; obj < 2; obj++) {\n        unordered_set<string> seen;\n        seen.reserve(64);\n\n        auto push_candidate = [&](Candidate&& c) {\n            string key = occ_key(c.occ);\n            if (seen.insert(key).second) cand[obj].push_back(std::move(c));\n        };\n\n        for (auto &prm : dpParams) {\n            if (elapsed_sec() > timeLimit && !cand[obj].empty()) break;\n            push_candidate(build_candidate_dp(obj, core, prm));\n        }\n\n        for (int pat = 0; pat < 4; pat++) {\n            if (elapsed_sec() > timeLimit && !cand[obj].empty()) break;\n            bool revA = (pat >> 1) & 1;\n            bool revB = pat & 1;\n            push_candidate(build_candidate_group_shift(obj, core, revA, revB, 0));\n        }\n\n        int shift1 = max(1, D / 3);\n        int shift2 = max(1, (2 * D) / 3);\n        push_candidate(build_candidate_group_shift(obj, core, false, false, shift1));\n        push_candidate(build_candidate_group_shift(obj, core, true, true, shift2));\n\n        if (cand[obj].empty()) {\n            push_candidate(build_candidate_dp(obj, core, dpParams[0]));\n        }\n    }\n\n    for (auto &c1 : cand[0]) {\n        if (elapsed_sec() > timeLimit + 0.04) break;\n        for (auto &c2 : cand[1]) {\n            PairPlan plan = make_pair_plan(c1, c2);\n            long double sc = core.scoreCore + plan.extraScore;\n            if (!res.ok || sc < res.score) {\n                res.ok = true;\n                res.score = sc;\n                res.c1 = c1;\n                res.c2 = c2;\n                res.plan = std::move(plan);\n            }\n        }\n    }\n\n    if (!res.ok) return res;\n\n    vector<pair<Param,int>> guidedCfgs = {\n        {{+1, 12000,  400, 91},  90000},\n        {{-1, 12000,  400, 92},  90000},\n        {{+1,  4000, 1400, 93},  30000},\n        {{-1,  4000, 1400, 94},  30000},\n    };\n\n    for (int round = 0; round < 2; round++) {\n        if (elapsed_sec() > timeLimit + 0.06) break;\n        bool improved = false;\n\n        for (int side = 0; side < 2; side++) {\n            if (elapsed_sec() > timeLimit + 0.06) break;\n\n            unordered_set<string> seen;\n            seen.reserve(guidedCfgs.size() * 2 + 1);\n\n            const array<uint8_t, MAXN>& pref = (side == 0 ? res.c2.occ : res.c1.occ);\n            for (auto &cfg : guidedCfgs) {\n                Candidate gc = build_candidate_dp(side, core, cfg.first, &pref, cfg.second);\n                string key = occ_key(gc.occ);\n                if (!seen.insert(key).second) continue;\n\n                long double sc;\n                PairPlan plan;\n                if (side == 0) {\n                    plan = make_pair_plan(gc, res.c2);\n                    sc = core.scoreCore + plan.extraScore;\n                    if (sc + 1e-15L < res.score) {\n                        improved = true;\n                        res.score = sc;\n                        res.c1 = std::move(gc);\n                        res.plan = std::move(plan);\n                    }\n                } else {\n                    plan = make_pair_plan(res.c1, gc);\n                    sc = core.scoreCore + plan.extraScore;\n                    if (sc + 1e-15L < res.score) {\n                        improved = true;\n                        res.score = sc;\n                        res.c2 = std::move(gc);\n                        res.plan = std::move(plan);\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return res;\n}\n\nCandidate build_random_candidate(int obj, const CoreInfo& core, const Candidate& other, XorShift64& rng) {\n    int typ = rng.nextInt(100);\n    if (typ < 75) {\n        static const int AV[] = {120000, 80000, 40000, 20000, 10000, 4000, 1500, 600};\n        static const int BV[] = {0, 50, 150, 400, 900, 1800, 3500};\n        static const int OV[] = {0, 3000, 8000, 20000, 60000, 150000};\n\n        Param prm;\n        prm.dir = (rng.nextInt(2) ? +1 : -1);\n        prm.alpha = AV[rng.nextInt((int)(sizeof(AV) / sizeof(AV[0])))];\n        prm.beta  = BV[rng.nextInt((int)(sizeof(BV) / sizeof(BV[0])))];\n        prm.seed  = (int)(rng.next() & 0x7fffffff);\n\n        bool usePref = rng.nextInt(100) < 70;\n        int overlapBonus = OV[rng.nextInt((int)(sizeof(OV) / sizeof(OV[0])))];\n\n        if (usePref) return build_candidate_dp(obj, core, prm, &other.occ, overlapBonus);\n        return build_candidate_dp(obj, core, prm, nullptr, 0);\n    } else {\n        bool revA = rng.nextInt(2);\n        bool revB = rng.nextInt(2);\n        int shift = rng.nextInt(max(1, D));\n        return build_candidate_group_shift(obj, core, revA, revB, shift);\n    }\n}\n\nState perturb_state(const State& base, XorShift64& rng) {\n    State ns = base;\n    int typ = rng.nextInt(100);\n\n    if (typ < 45) {\n        int side = rng.nextInt(2);\n        if (side == 0) ns.c1 = build_random_candidate(0, ns.core, ns.c2, rng);\n        else ns.c2 = build_random_candidate(1, ns.core, ns.c1, rng);\n    } else {\n        int first = rng.nextInt(2);\n        if (first == 0) {\n            ns.c1 = build_random_candidate(0, ns.core, ns.c2, rng);\n            ns.c2 = build_random_candidate(1, ns.core, ns.c1, rng);\n        } else {\n            ns.c2 = build_random_candidate(1, ns.core, ns.c1, rng);\n            ns.c1 = build_random_candidate(0, ns.core, ns.c2, rng);\n        }\n    }\n\n    ns.plan = make_pair_plan(ns.c1, ns.c2);\n    ns.score = ns.core.scoreCore + ns.plan.extraScore;\n    ns.ok = true;\n    return ns;\n}\n\nvoid stochastic_refine_state(State& st, XorShift64& rng, double deadline) {\n    if (!st.ok) return;\n    build_runs(st.core);\n\n    unordered_set<string> seen1, seen2;\n    seen1.reserve(512);\n    seen2.reserve(512);\n    seen1.insert(occ_key(st.c1.occ));\n    seen2.insert(occ_key(st.c2.occ));\n\n    int iter = 0;\n    while (elapsed_sec() < deadline) {\n        ++iter;\n\n        if (iter % 6 == 0) {\n            int first = rng.nextInt(2);\n            if (first == 0) {\n                Candidate a = build_random_candidate(0, st.core, st.c2, rng);\n                Candidate b = build_random_candidate(1, st.core, a, rng);\n                PairPlan plan = make_pair_plan(a, b);\n                long double sc = st.core.scoreCore + plan.extraScore;\n                if (sc + 1e-15L < st.score) {\n                    st.score = sc;\n                    st.c1 = std::move(a);\n                    st.c2 = std::move(b);\n                    st.plan = std::move(plan);\n                    seen1.insert(occ_key(st.c1.occ));\n                    seen2.insert(occ_key(st.c2.occ));\n                }\n            } else {\n                Candidate b = build_random_candidate(1, st.core, st.c1, rng);\n                Candidate a = build_random_candidate(0, st.core, b, rng);\n                PairPlan plan = make_pair_plan(a, b);\n                long double sc = st.core.scoreCore + plan.extraScore;\n                if (sc + 1e-15L < st.score) {\n                    st.score = sc;\n                    st.c1 = std::move(a);\n                    st.c2 = std::move(b);\n                    st.plan = std::move(plan);\n                    seen1.insert(occ_key(st.c1.occ));\n                    seen2.insert(occ_key(st.c2.occ));\n                }\n            }\n            continue;\n        }\n\n        int side = (iter & 1);\n        Candidate cand = build_random_candidate(side, st.core, (side == 0 ? st.c2 : st.c1), rng);\n        string key = occ_key(cand.occ);\n        auto& seen = (side == 0 ? seen1 : seen2);\n        if (!seen.insert(key).second) continue;\n\n        PairPlan plan;\n        long double sc;\n        if (side == 0) {\n            plan = make_pair_plan(cand, st.c2);\n            sc = st.core.scoreCore + plan.extraScore;\n            if (sc + 1e-15L < st.score) {\n                st.score = sc;\n                st.c1 = std::move(cand);\n                st.plan = std::move(plan);\n            }\n        } else {\n            plan = make_pair_plan(st.c1, cand);\n            sc = st.core.scoreCore + plan.extraScore;\n            if (sc + 1e-15L < st.score) {\n                st.score = sc;\n                st.c2 = std::move(cand);\n                st.plan = std::move(plan);\n            }\n        }\n    }\n}\n\nvoid recombine_elites(vector<State>& elites, int K, State& bestState, double deadline) {\n    if (elites.size() <= 1) return;\n    sort(elites.begin(), elites.end(), [](const State& a, const State& b) { return a.score < b.score; });\n\n    int n = (int)elites.size();\n    vector<int> vis(n, 0);\n\n    for (int i = 0; i < n; i++) {\n        if (vis[i]) continue;\n        vector<State> group;\n        group.push_back(elites[i]);\n        vis[i] = 1;\n        for (int j = i + 1; j < n; j++) {\n            if (!vis[j] && same_core(elites[i], elites[j])) {\n                vis[j] = 1;\n                group.push_back(elites[j]);\n            }\n        }\n        if ((int)group.size() <= 1) continue;\n\n        for (int a = 0; a < (int)group.size(); a++) {\n            for (int b = 0; b < (int)group.size(); b++) {\n                if (elapsed_sec() > deadline) goto END_RECOMB;\n                State ns;\n                ns.ok = true;\n                ns.core = group[a].core;\n                ns.c1 = group[a].c1;\n                ns.c2 = group[b].c2;\n                ns.plan = make_pair_plan(ns.c1, ns.c2);\n                ns.score = ns.core.scoreCore + ns.plan.extraScore;\n                insert_elite(elites, ns, K);\n            }\n        }\n    }\n\nEND_RECOMB:\n    sort(elites.begin(), elites.end(), [](const State& a, const State& b) { return a.score < b.score; });\n    if (!elites.empty() && (!bestState.ok || elites[0].score < bestState.score)) bestState = elites[0];\n}\n\nvoid intensify_state(State& st, const vector<Param>& baseParams, double deadline) {\n    if (!st.ok) return;\n    build_runs(st.core);\n\n    vector<pair<Param,int>> guidedCfgs = {\n        {{+1, 12000,  400, 191},  90000},\n        {{-1, 12000,  400, 192},  90000},\n        {{+1,  4000, 1400, 193},  30000},\n        {{-1,  4000, 1400, 194},  30000},\n        {{+1, 80000,    0, 195},      0},\n        {{-1, 80000,    0, 196},      0},\n        {{+1, 15000,  600, 197},  60000},\n        {{-1, 15000,  600, 198},  60000},\n    };\n\n    int shifts[4] = {0, max(1, D / 4), max(1, D / 2), max(1, (3 * D) / 4)};\n\n    for (int round = 0; round < 3 && elapsed_sec() < deadline; round++) {\n        bool improved = false;\n\n        for (int side = 0; side < 2 && elapsed_sec() < deadline; side++) {\n            unordered_set<string> seen;\n            seen.reserve(256);\n\n            auto try_cand = [&](Candidate&& cand) {\n                string key = occ_key(cand.occ);\n                if (!seen.insert(key).second) return;\n\n                PairPlan plan;\n                long double sc;\n                if (side == 0) {\n                    plan = make_pair_plan(cand, st.c2);\n                    sc = st.core.scoreCore + plan.extraScore;\n                    if (sc + 1e-15L < st.score) {\n                        st.score = sc;\n                        st.c1 = std::move(cand);\n                        st.plan = std::move(plan);\n                        improved = true;\n                    }\n                } else {\n                    plan = make_pair_plan(st.c1, cand);\n                    sc = st.core.scoreCore + plan.extraScore;\n                    if (sc + 1e-15L < st.score) {\n                        st.score = sc;\n                        st.c2 = std::move(cand);\n                        st.plan = std::move(plan);\n                        improved = true;\n                    }\n                }\n            };\n\n            const array<uint8_t, MAXN>& pref = (side == 0 ? st.c2.occ : st.c1.occ);\n\n            for (auto &prm : baseParams) {\n                if (elapsed_sec() > deadline) break;\n                try_cand(build_candidate_dp(side, st.core, prm));\n            }\n            for (auto &cfg : guidedCfgs) {\n                if (elapsed_sec() > deadline) break;\n                if (cfg.second == 0) try_cand(build_candidate_dp(side, st.core, cfg.first));\n                else try_cand(build_candidate_dp(side, st.core, cfg.first, &pref, cfg.second));\n            }\n            for (int pat = 0; pat < 4 && elapsed_sec() < deadline; pat++) {\n                bool revA = (pat >> 1) & 1;\n                bool revB = pat & 1;\n                for (int sh : shifts) {\n                    if (elapsed_sec() > deadline) break;\n                    try_cand(build_candidate_group_shift(side, st.core, revA, revB, sh));\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid fill_line_seg(array<int, MAXN>& out, LineSeg s, int len, int label) {\n    for (int t = 0; t < len; t++) {\n        int x = s.x, y = s.y, z = s.z;\n        if (s.axis == 0) x += t;\n        else if (s.axis == 1) y += t;\n        else z += t;\n        out[idx3(x, y, z)] = label;\n    }\n}\nvoid advance_seg(LineSeg& s, int used) {\n    if (s.axis == 0) s.x += used;\n    else if (s.axis == 1) s.y += used;\n    else s.z += used;\n    s.len -= used;\n}\n\nvoid assign_final_labels(\n    const CoreInfo& core,\n    const Candidate& cand1,\n    const Candidate& cand2,\n    const PairPlan& plan,\n    array<int, MAXN>& out1,\n    array<int, MAXN>& out2,\n    int& nblocks\n) {\n    out1.fill(0);\n    out2.fill(0);\n    nblocks = 0;\n\n    for (int cid = 0; cid < (int)commonComps.size(); cid++) {\n        if (!core.keep[cid]) continue;\n        ++nblocks;\n        for (int id : commonComps[cid].cells) {\n            out1[id] = nblocks;\n            out2[id] = nblocks;\n        }\n    }\n\n    vector<char> used1(cand1.comps.size(), 0), used2(cand2.comps.size(), 0);\n    for (auto [i, j] : plan.matchedExtra) {\n        used1[i] = 1;\n        used2[j] = 1;\n        ++nblocks;\n        for (int id : cand1.comps[i].cells) out1[id] = nblocks;\n        for (int id : cand2.comps[j].cells) out2[id] = nblocks;\n    }\n\n    vector<LineSeg> s1, s2;\n    for (int i = 0; i < (int)cand1.comps.size(); i++) if (!used1[i]) {\n        append_component_axis_segments(cand1.comps[i], plan.compAxis1[i], s1);\n    }\n    for (int i = 0; i < (int)cand2.comps.size(); i++) if (!used2[i]) {\n        append_component_axis_segments(cand2.comps[i], plan.compAxis2[i], s2);\n    }\n\n    priority_queue<LineSeg, vector<LineSeg>, LineSegCmp> pq1, pq2;\n    for (auto &s : s1) pq1.push(s);\n    for (auto &s : s2) pq2.push(s);\n\n    while (!pq1.empty() && !pq2.empty()) {\n        LineSeg a = pq1.top(); pq1.pop();\n        LineSeg b = pq2.top(); pq2.pop();\n        int m = min(a.len, b.len);\n        ++nblocks;\n        fill_line_seg(out1, a, m, nblocks);\n        fill_line_seg(out2, b, m, nblocks);\n\n        if (a.len > m) {\n            advance_seg(a, m);\n            pq1.push(a);\n        }\n        if (b.len > m) {\n            advance_seg(b, m);\n            pq2.push(b);\n        }\n    }\n    while (!pq1.empty()) {\n        LineSeg a = pq1.top(); pq1.pop();\n        ++nblocks;\n        fill_line_seg(out1, a, a.len, nblocks);\n    }\n    while (!pq2.empty()) {\n        LineSeg b = pq2.top(); pq2.pop();\n        ++nblocks;\n        fill_line_seg(out2, b, b.len, nblocks);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> D;\n    Ncells = D * D * D;\n    init_rotations();\n\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) cin >> fstr[i][z];\n        for (int z = 0; z < D; z++) cin >> rstr[i][z];\n    }\n\n    for (int obj = 0; obj < 2; obj++) {\n        for (int z = 0; z < D; z++) {\n            actXMask[obj][z] = 0;\n            actYMask[obj][z] = 0;\n            actXList[obj][z].clear();\n            actYList[obj][z].clear();\n\n            for (int x = 0; x < D; x++) {\n                if (fstr[obj][z][x] == '1') {\n                    actXMask[obj][z] |= (uint16_t(1) << x);\n                    actXList[obj][z].push_back(x);\n                }\n            }\n            for (int y = 0; y < D; y++) {\n                if (rstr[obj][z][y] == '1') {\n                    actYMask[obj][z] |= (uint16_t(1) << y);\n                    actYList[obj][z].push_back(y);\n                }\n            }\n\n            for (int x = 0; x < D; x++) for (int y = 0; y < D; y++) {\n                activeCell[obj][x][y][z] =\n                    (fstr[obj][z][x] == '1' && rstr[obj][z][y] == '1') ? 1 : 0;\n            }\n        }\n    }\n\n    build_full_common_components();\n\n    uint64_t seed = 1469598103934665603ull;\n    seed ^= (uint64_t)D + 0x9e3779b97f4a7c15ull;\n    seed *= 1099511628211ull;\n    for (int i = 0; i < 2; i++) {\n        for (int z = 0; z < D; z++) for (char c : fstr[i][z]) {\n            seed ^= (uint64_t)c;\n            seed *= 1099511628211ull;\n        }\n        for (int z = 0; z < D; z++) for (char c : rstr[i][z]) {\n            seed ^= (uint64_t)c;\n            seed *= 1099511628211ull;\n        }\n    }\n    XorShift64 rng(seed);\n\n    vector<Param> dpParams = {\n        {+1, 100000,    0, 1},\n        {-1, 100000,    0, 1},\n        {+1,  25000,  200, 2},\n        {-1,  25000,  200, 2},\n        {+1,   6000, 1200, 3},\n        {-1,   6000, 1200, 3},\n    };\n\n    vector<int> thresholds = select_thresholds();\n\n    State bestState;\n    vector<State> elites;\n    const int ELITE_K = 6;\n\n    vector<CoreInfo> cores;\n    for (int th : thresholds) cores.push_back(build_core_by_threshold(th));\n\n    sort(cores.begin(), cores.end(), [&](const CoreInfo& a, const CoreInfo& b) {\n        long double la = a.scoreCore + (long double)abs(a.remVol[0] - a.remVol[1]);\n        long double lb = b.scoreCore + (long double)abs(b.remVol[0] - b.remVol[1]);\n        return la < lb;\n    });\n\n    for (const CoreInfo& core : cores) {\n        if (elapsed_sec() > 3.80) break;\n        long double lb = core.scoreCore + (long double)abs(core.remVol[0] - core.remVol[1]);\n        if (bestState.ok && lb >= bestState.score - 1e-15L) continue;\n\n        EvalResult ev = evaluate_core(core, dpParams, 4.02);\n        if (ev.ok) {\n            State st = make_state(core, ev);\n            insert_elite(elites, st, ELITE_K);\n            if (!bestState.ok || st.score < bestState.score) bestState = st;\n        }\n    }\n\n    if (!bestState.ok) {\n        CoreInfo core = build_core_by_threshold((int)1e9);\n        EvalResult ev = evaluate_core(core, dpParams, 4.02);\n        if (ev.ok) {\n            bestState = make_state(core, ev);\n            insert_elite(elites, bestState, ELITE_K);\n        } else {\n            bestState.ok = true;\n            bestState.core = core;\n            build_runs(core);\n            bestState.c1 = build_candidate_dp(0, core, dpParams[0]);\n            bestState.c2 = build_candidate_dp(1, core, dpParams[0]);\n            bestState.plan = make_pair_plan(bestState.c1, bestState.c2);\n            bestState.score = core.scoreCore + bestState.plan.extraScore;\n            insert_elite(elites, bestState, ELITE_K);\n        }\n    }\n\n    if (elapsed_sec() < 4.38) {\n        recombine_elites(elites, ELITE_K, bestState, 4.45);\n    }\n\n    if (!commonComps.empty() && elapsed_sec() < 4.58) {\n        vector<char> curKeep = bestState.core.keep;\n\n        for (int phase = 0; phase < 2 && elapsed_sec() < 4.76; phase++) {\n            vector<int> rem, add;\n            for (int i = 0; i < (int)commonComps.size(); i++) {\n                if (curKeep[i]) rem.push_back(i);\n                else add.push_back(i);\n            }\n            sort(rem.begin(), rem.end(), [&](int a, int b) {\n                if (commonComps[a].vol != commonComps[b].vol) return commonComps[a].vol < commonComps[b].vol;\n                return a < b;\n            });\n            sort(add.begin(), add.end(), [&](int a, int b) {\n                if (commonComps[a].vol != commonComps[b].vol) return commonComps[a].vol > commonComps[b].vol;\n                return a < b;\n            });\n\n            vector<int> order;\n            int LIM1 = min<int>(12, rem.size());\n            int LIM2 = min<int>(12, add.size());\n            for (int i = 0; i < LIM1; i++) order.push_back(rem[i]);\n            for (int i = 0; i < LIM2; i++) order.push_back(add[i]);\n            if (phase == 1) reverse(order.begin(), order.end());\n\n            bool improved = false;\n\n            for (int cid : order) {\n                if (elapsed_sec() > 4.82) break;\n\n                vector<char> nk = curKeep;\n                nk[cid] ^= 1;\n                CoreInfo nc = build_core_from_keep(nk);\n                long double lb = nc.scoreCore + (long double)abs(nc.remVol[0] - nc.remVol[1]);\n                if (lb >= bestState.score - 1e-15L) continue;\n\n                EvalResult ev = evaluate_core(nc, dpParams, 4.70);\n                if (ev.ok) {\n                    State st = make_state(nc, ev);\n                    insert_elite(elites, st, ELITE_K);\n                    if (st.score + 1e-15L < bestState.score) {\n                        improved = true;\n                        curKeep = std::move(nk);\n                        bestState = st;\n                    }\n                }\n            }\n            if (!improved) break;\n        }\n    }\n\n    if (elites.empty()) elites.push_back(bestState);\n    sort(elites.begin(), elites.end(), [](const State& a, const State& b) { return a.score < b.score; });\n    if (elites[0].score < bestState.score) bestState = elites[0];\n\n    // exploration phase\n    double beamDeadline = 5.40;\n    int ptr = 0;\n    while (elapsed_sec() < beamDeadline) {\n        if (elites.empty()) break;\n        int id = ptr % (int)elites.size();\n        ptr++;\n\n        double now = elapsed_sec();\n        double slice = min(beamDeadline, now + 0.06);\n        stochastic_refine_state(elites[id], rng, slice);\n\n        if (elapsed_sec() < beamDeadline) {\n            State cand = perturb_state(elites[id], rng);\n            if ((int)elites.size() < ELITE_K || cand.score + 1e-15L < elites.back().score) {\n                insert_elite(elites, cand, ELITE_K);\n            }\n        }\n\n        if (ptr % 4 == 0 && elapsed_sec() < beamDeadline) {\n            recombine_elites(elites, ELITE_K, bestState, min(beamDeadline, elapsed_sec() + 0.025));\n        }\n\n        sort(elites.begin(), elites.end(), [](const State& a, const State& b) { return a.score < b.score; });\n        if (!elites.empty() && elites[0].score < bestState.score) bestState = elites[0];\n    }\n\n    // final deterministic intensification on the current best\n    if (elapsed_sec() < 5.68) {\n        intensify_state(bestState, dpParams, 5.72);\n    }\n\n    array<int, MAXN> out1, out2;\n    int nblocks = 0;\n    assign_final_labels(bestState.core, bestState.c1, bestState.c2, bestState.plan, out1, out2, nblocks);\n\n    cout << nblocks << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out1[i];\n    }\n    cout << '\\n';\n    for (int i = 0; i < Ncells; i++) {\n        if (i) cout << ' ';\n        cout << out2[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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 leader(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool merge(int a, int b) {\n        a = leader(a);\n        b = leader(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Edge {\n    int u, v, w;\n};\n\nstruct Candidate {\n    vector<int> P;\n    vector<char> B;\n    int covered = -1;\n    long long cost = (1LL << 62);\n};\n\nstruct InitialState {\n    vector<int> P;\n    vector<char> B;\n};\n\nclass Solver {\npublic:\n    int N, M, K;\n    vector<int> xs, ys;\n    vector<Edge> edges;\n    vector<int> as, bs;\n\n    vector<vector<int>> req;                    // req[i][k] = min radius to cover resident k, or 5001\n    vector<vector<pair<int,int>>> lists;        // sorted (required radius, resident id)\n    vector<vector<int>> incident;\n    vector<vector<int>> eidMat;\n\n    vector<vector<long long>> sp;\n    vector<vector<int>> nxt;\n\n    chrono::steady_clock::time_point t0;\n\n    static constexpr long long INF64 = (1LL << 60);\n    static constexpr double HARD_LIMIT = 1.90;\n\n    void input() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M >> K;\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) cin >> xs[i] >> ys[i];\n\n        edges.resize(M);\n        incident.assign(N, {});\n        eidMat.assign(N, vector<int>(N, -1));\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, v, w};\n            incident[u].push_back(i);\n            incident[v].push_back(i);\n            eidMat[u][v] = eidMat[v][u] = i;\n        }\n\n        as.resize(K);\n        bs.resize(K);\n        for (int k = 0; k < K; k++) cin >> as[k] >> bs[k];\n    }\n\n    static int ceil_sqrt_ll(long long x) {\n        long long r = sqrt((long double)x);\n        while (r * r < x) ++r;\n        while (r > 0 && (r - 1) * (r - 1) >= x) --r;\n        return (int)r;\n    }\n\n    void precompute() {\n        req.assign(N, vector<int>(K, 5001));\n        lists.assign(N, {});\n        for (int i = 0; i < N; i++) {\n            lists[i].reserve(K / 3);\n            for (int k = 0; k < K; k++) {\n                long long dx = (long long)xs[i] - as[k];\n                long long dy = (long long)ys[i] - bs[k];\n                long long d2 = dx * dx + dy * dy;\n                int r = ceil_sqrt_ll(d2);\n                if (r <= 5000) {\n                    req[i][k] = r;\n                    lists[i].push_back({r, k});\n                }\n            }\n            sort(lists[i].begin(), lists[i].end());\n        }\n\n        sp.assign(N, vector<long long>(N, INF64));\n        nxt.assign(N, vector<int>(N, -1));\n        for (int i = 0; i < N; i++) {\n            sp[i][i] = 0;\n            nxt[i][i] = i;\n        }\n        for (int e = 0; e < M; e++) {\n            auto [u, v, w] = edges[e];\n            if ((long long)w < sp[u][v]) {\n                sp[u][v] = sp[v][u] = w;\n                nxt[u][v] = v;\n                nxt[v][u] = u;\n            }\n        }\n        for (int k = 0; k < N; k++) {\n            for (int i = 0; i < N; i++) if (sp[i][k] < INF64) {\n                for (int j = 0; j < N; j++) if (sp[k][j] < INF64) {\n                    long long nd = sp[i][k] + sp[k][j];\n                    if (nd < sp[i][j]) {\n                        sp[i][j] = nd;\n                        nxt[i][j] = nxt[i][k];\n                    }\n                }\n            }\n        }\n\n        t0 = chrono::steady_clock::now();\n    }\n\n    double elapsed() const {\n        auto t = chrono::steady_clock::now();\n        return chrono::duration<double>(t - t0).count();\n    }\n\n    static bool better(const Candidate& a, const Candidate& b, int K) {\n        if (a.covered != b.covered) return a.covered > b.covered;\n        if (a.covered == K) return a.cost < b.cost;\n        return a.cost < b.cost;\n    }\n\n    long long edge_cost(const vector<char>& B) const {\n        long long c = 0;\n        for (int e = 0; e < M; e++) if (B[e]) c += edges[e].w;\n        return c;\n    }\n\n    long long power_cost(const vector<int>& P) const {\n        long long c = 0;\n        for (int i = 0; i < N; i++) c += 1LL * P[i] * P[i];\n        return c;\n    }\n\n    vector<long double> make_gain_table(long double gamma) const {\n        vector<long double> gain(K + 1, 0);\n        if (fabsl(gamma - 1.0L) < 1e-18L) {\n            for (int i = 1; i <= K; i++) gain[i] = (long double)i;\n        } else {\n            for (int i = 1; i <= K; i++) gain[i] = powl((long double)i, gamma);\n        }\n        return gain;\n    }\n\n    vector<int> reconstruct_path_vertices(int s, int t) const {\n        vector<int> path;\n        if (nxt[s][t] == -1) return path;\n        int cur = s;\n        path.push_back(cur);\n        while (cur != t) {\n            cur = nxt[cur][t];\n            path.push_back(cur);\n        }\n        return path;\n    }\n\n    void recompute_nearest_tree(\n        const vector<char>& inTree,\n        vector<long long>& distToTree,\n        vector<int>& nearTree\n    ) const {\n        distToTree.assign(N, INF64);\n        nearTree.assign(N, -1);\n        for (int i = 0; i < N; i++) {\n            if (inTree[i]) {\n                distToTree[i] = 0;\n                nearTree[i] = i;\n                continue;\n            }\n            long long best = INF64;\n            int bestv = -1;\n            for (int v = 0; v < N; v++) if (inTree[v]) {\n                if (sp[v][i] < best) {\n                    best = sp[v][i];\n                    bestv = v;\n                }\n            }\n            distToTree[i] = best;\n            nearTree[i] = bestv;\n        }\n    }\n\n    vector<char> terminals_from_P(const vector<int>& P) const {\n        vector<char> term(N, 0);\n        term[0] = 1;\n        for (int i = 0; i < N; i++) if (P[i] > 0) term[i] = 1;\n        return term;\n    }\n\n    vector<char> tree_vertices(const vector<char>& B) const {\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 (int eid : incident[v]) if (B[eid]) {\n                int to = edges[eid].u ^ edges[eid].v ^ v;\n                if (!vis[to]) {\n                    vis[to] = 1;\n                    q.push(to);\n                }\n            }\n        }\n        return vis;\n    }\n\n    void prune_nonterminal_leaves(vector<char>& B, const vector<char>& terminal) const {\n        vector<int> deg(N, 0);\n        for (int e = 0; e < M; e++) if (B[e]) {\n            deg[edges[e].u]++;\n            deg[edges[e].v]++;\n        }\n\n        queue<int> q;\n        for (int v = 0; v < N; v++) {\n            if (v != 0 && !terminal[v] && deg[v] == 1) q.push(v);\n        }\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            if (v == 0 || terminal[v] || deg[v] != 1) continue;\n\n            int remE = -1, to = -1;\n            for (int eid : incident[v]) if (B[eid]) {\n                remE = eid;\n                to = edges[eid].u ^ edges[eid].v ^ v;\n                break;\n            }\n            if (remE == -1) continue;\n\n            B[remE] = 0;\n            deg[v]--;\n            deg[to]--;\n            if (to != 0 && !terminal[to] && deg[to] == 1) q.push(to);\n        }\n    }\n\n    vector<char> optimize_tree_same_vertices(vector<char> B, const vector<char>& terminal) const {\n        vector<char> inV = tree_vertices(B);\n        vector<int> cand;\n        cand.reserve(M);\n        for (int e = 0; e < M; e++) {\n            int u = edges[e].u, v = edges[e].v;\n            if (inV[u] && inV[v]) cand.push_back(e);\n        }\n        sort(cand.begin(), cand.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        DSU dsu(N);\n        vector<char> B2(M, 0);\n        for (int eid : cand) {\n            int u = edges[eid].u, v = edges[eid].v;\n            if (dsu.merge(u, v)) B2[eid] = 1;\n        }\n        prune_nonterminal_leaves(B2, terminal);\n\n        if (edge_cost(B2) < edge_cost(B)) return B2;\n        return B;\n    }\n\n    vector<char> build_tree_metric(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n\n        vector<int> ids;\n        ids.push_back(0);\n        for (int i = 1; i < N; i++) if (terminal[i]) ids.push_back(i);\n\n        int T = (int)ids.size();\n        if (T <= 1) return used;\n\n        vector<long long> minD(T, INF64);\n        vector<int> par(T, -1);\n        vector<char> vis(T, 0);\n        minD[0] = 0;\n\n        for (int it = 0; it < T; it++) {\n            int v = -1;\n            for (int i = 0; i < T; i++) {\n                if (!vis[i] && (v == -1 || minD[i] < minD[v])) v = i;\n            }\n            vis[v] = 1;\n            for (int u = 0; u < T; u++) if (!vis[u]) {\n                if (sp[ids[v]][ids[u]] < minD[u]) {\n                    minD[u] = sp[ids[v]][ids[u]];\n                    par[u] = v;\n                }\n            }\n        }\n\n        vector<char> cand(M, 0);\n        vector<int> candEdges;\n        for (int i = 1; i < T; i++) {\n            auto path = reconstruct_path_vertices(ids[i], ids[par[i]]);\n            for (int j = 0; j + 1 < (int)path.size(); j++) {\n                int a = path[j], b = path[j + 1];\n                int eid = eidMat[a][b];\n                if (eid >= 0 && !cand[eid]) {\n                    cand[eid] = 1;\n                    candEdges.push_back(eid);\n                }\n            }\n        }\n\n        sort(candEdges.begin(), candEdges.end(), [&](int e1, int e2) {\n            if (edges[e1].w != edges[e2].w) return edges[e1].w < edges[e2].w;\n            return e1 < e2;\n        });\n\n        DSU dsu(N);\n        for (int eid : candEdges) {\n            int u = edges[eid].u, v = edges[eid].v;\n            if (dsu.merge(u, v)) used[eid] = 1;\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        used = optimize_tree_same_vertices(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_sph(const vector<char>& terminal) const {\n        vector<char> used(M, 0);\n        vector<char> inTree(N, 0);\n        vector<char> left = terminal;\n        inTree[0] = 1;\n        left[0] = 0;\n\n        int rem = 0;\n        for (int i = 0; i < N; i++) if (left[i]) rem++;\n\n        if (rem == 0) return used;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        while (rem > 0) {\n            int best = -1;\n            long long bestD = INF64;\n            for (int i = 0; i < N; i++) if (left[i]) {\n                if (distToTree[i] < bestD) {\n                    bestD = distToTree[i];\n                    best = i;\n                }\n            }\n            if (best == -1) break;\n\n            int from = nearTree[best];\n            auto path = reconstruct_path_vertices(from, best);\n\n            int lastTreeIdx = 0;\n            for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n            for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                int u = path[i], v = path[i + 1];\n                int eid = eidMat[u][v];\n                if (eid >= 0) used[eid] = 1;\n                inTree[u] = 1;\n                inTree[v] = 1;\n            }\n            left[best] = 0;\n            rem--;\n\n            recompute_nearest_tree(inTree, distToTree, nearTree);\n        }\n\n        prune_nonterminal_leaves(used, terminal);\n        used = optimize_tree_same_vertices(used, terminal);\n        return used;\n    }\n\n    vector<char> build_tree_best(const vector<char>& terminal) const {\n        auto b1 = build_tree_metric(terminal);\n        auto b2 = build_tree_sph(terminal);\n        if (edge_cost(b2) < edge_cost(b1)) return b2;\n        return b1;\n    }\n\n    int count_covered_by_P(const vector<int>& P) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        if (active.empty()) return 0;\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n        return cov;\n    }\n\n    void reduce_powers(vector<int>& P) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        if (active.empty()) return;\n\n        vector<int> cnt(K, 0);\n        for (int i : active) {\n            for (const auto& [d, rid] : lists[i]) {\n                if (d > P[i]) break;\n                cnt[rid]++;\n            }\n        }\n\n        while (true) {\n            bool changed = false;\n            sort(active.begin(), active.end(), [&](int a, int b) {\n                if (P[a] != P[b]) return P[a] > P[b];\n                return a < b;\n            });\n\n            for (int i : active) {\n                if (P[i] == 0) continue;\n                int oldP = P[i];\n                int newP = 0;\n\n                for (const auto& [d, rid] : lists[i]) {\n                    if (d > oldP) break;\n                    if (cnt[rid] == 1) newP = d;\n                }\n\n                if (newP < oldP) {\n                    for (const auto& [d, rid] : lists[i]) {\n                        if (d > oldP) break;\n                        if (d > newP) cnt[rid]--;\n                    }\n                    P[i] = newP;\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> greedy_cover_subset(\n        const vector<char>& allowed,\n        const vector<int>& Pinit,\n        const vector<char>& needMask,\n        long double gamma,\n        int banned = -1\n    ) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P = Pinit;\n        vector<char> uncoveredNeed = needMask;\n\n        int rem = 0;\n        for (int k = 0; k < K; k++) if (needMask[k]) rem++;\n        if (rem == 0) return P;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (uncoveredNeed[k]) {\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    uncoveredNeed[k] = 0;\n                    rem--;\n                    break;\n                }\n            }\n        }\n        if (rem == 0) return P;\n\n        vector<int> curPos(N, 0);\n        for (int i = 0; i < N; i++) {\n            auto it = upper_bound(lists[i].begin(), lists[i].end(), make_pair(P[i], INT_MAX));\n            curPos[i] = (int)(it - lists[i].begin());\n        }\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                if (!allowed[i] || i == banned) continue;\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int rid = vec[idx].second;\n                    if (uncoveredNeed[rid]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq);\n                    long double metric = num / gain[newcov];\n\n                    bool take = false;\n                    if (metric < bestMetric - 1e-18L) take = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) take = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) take = true;\n                    }\n\n                    if (take) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (uncoveredNeed[rid]) {\n                    uncoveredNeed[rid] = 0;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return P;\n    }\n\n    vector<int> greedy_on_allowed_gamma(const vector<char>& allowed, long double gamma, int banned = -1) const {\n        vector<int> P0(N, 0);\n        vector<char> need(K, 1);\n        return greedy_cover_subset(allowed, P0, need, gamma, banned);\n    }\n\n    InitialState greedy_initial(long double alpha, long double gamma) const {\n        vector<long double> gain = make_gain_table(gamma);\n\n        vector<int> P(N, 0);\n        vector<int> curPos(N, 0);\n        vector<char> covered(K, 0);\n        vector<char> usedEdge(M, 0);\n        vector<char> inTree(N, 0);\n        inTree[0] = 1;\n\n        vector<long long> distToTree;\n        vector<int> nearTree;\n        recompute_nearest_tree(inTree, distToTree, nearTree);\n\n        int rem = K;\n\n        while (rem > 0) {\n            long double bestMetric = 1e100L;\n            long double bestNum = 1e100L;\n            int bestStation = -1;\n            int bestRadius = -1;\n            int bestGain = 0;\n\n            for (int i = 0; i < N; i++) {\n                long double conn = inTree[i] ? 0.0L : alpha * (long double)distToTree[i];\n                long long curSq = 1LL * P[i] * P[i];\n                int newcov = 0;\n\n                const auto& vec = lists[i];\n                for (int idx = curPos[i]; idx < (int)vec.size(); idx++) {\n                    int d = vec[idx].first;\n                    int r = vec[idx].second;\n                    if (!covered[r]) ++newcov;\n                    if (newcov == 0) continue;\n\n                    long double num = (long double)(1LL * d * d - curSq) + conn;\n                    long double metric = num / gain[newcov];\n\n                    bool take = false;\n                    if (metric < bestMetric - 1e-18L) take = true;\n                    else if (fabsl(metric - bestMetric) <= 1e-18L) {\n                        if (num < bestNum - 1e-12L) take = true;\n                        else if (fabsl(num - bestNum) <= 1e-12L && newcov > bestGain) take = true;\n                    }\n\n                    if (take) {\n                        bestMetric = metric;\n                        bestNum = num;\n                        bestStation = i;\n                        bestRadius = d;\n                        bestGain = newcov;\n                    }\n                }\n            }\n\n            if (bestStation == -1) break;\n\n            if (!inTree[bestStation]) {\n                int from = nearTree[bestStation];\n                auto path = reconstruct_path_vertices(from, bestStation);\n\n                int lastTreeIdx = 0;\n                for (int i = 0; i < (int)path.size(); i++) if (inTree[path[i]]) lastTreeIdx = i;\n                for (int i = lastTreeIdx; i + 1 < (int)path.size(); i++) {\n                    int u = path[i], v = path[i + 1];\n                    int eid = eidMat[u][v];\n                    if (eid >= 0) usedEdge[eid] = 1;\n                    inTree[u] = 1;\n                    inTree[v] = 1;\n                }\n\n                recompute_nearest_tree(inTree, distToTree, nearTree);\n            }\n\n            P[bestStation] = bestRadius;\n            const auto& vec = lists[bestStation];\n            int idx = curPos[bestStation];\n            while (idx < (int)vec.size() && vec[idx].first <= bestRadius) {\n                int rid = vec[idx].second;\n                if (!covered[rid]) {\n                    covered[rid] = 1;\n                    rem--;\n                }\n                ++idx;\n            }\n            curPos[bestStation] = idx;\n        }\n\n        return {P, usedEdge};\n    }\n\n    Candidate make_candidate(const vector<int>& Pin, const vector<char>& Bin, bool normalize = true) const {\n        vector<int> P = Pin;\n        vector<char> B = Bin;\n\n        if (normalize) {\n            vector<char> reach = tree_vertices(B);\n            for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n            for (int e = 0; e < M; e++) if (B[e]) {\n                int u = edges[e].u, v = edges[e].v;\n                if (!(reach[u] && reach[v])) B[e] = 0;\n            }\n\n            vector<char> terminal(N, 0);\n            terminal[0] = 1;\n            for (int i = 0; i < N; i++) if (P[i] > 0) terminal[i] = 1;\n            prune_nonterminal_leaves(B, terminal);\n\n            reach = tree_vertices(B);\n            for (int i = 0; i < N; i++) if (!reach[i]) P[i] = 0;\n        }\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n\n        int cov = 0;\n        for (int k = 0; k < K; k++) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) ++cov;\n        }\n\n        long long cost = power_cost(P) + edge_cost(B);\n        return {P, B, cov, cost};\n    }\n\n    Candidate basic_improve(Candidate cur, int rounds) const {\n        for (int it = 0; it < rounds; it++) {\n            if (elapsed() > HARD_LIMIT) break;\n\n            Candidate bestRound = cur;\n\n            auto B0 = build_tree_best(terminals_from_P(cur.P));\n            Candidate c0 = make_candidate(cur.P, B0);\n            if (better(c0, bestRound, K)) bestRound = c0;\n\n            vector<char> allowed = tree_vertices(bestRound.B);\n\n            static const long double gammas[] = {1.0L, 1.10L};\n            for (long double g : gammas) {\n                if (elapsed() > HARD_LIMIT) break;\n                vector<int> P = greedy_on_allowed_gamma(allowed, g);\n                if (count_covered_by_P(P) < K) continue;\n                reduce_powers(P);\n                auto B = build_tree_best(terminals_from_P(P));\n                Candidate c = make_candidate(P, B);\n                if (better(c, bestRound, K)) bestRound = c;\n            }\n\n            if (better(bestRound, cur, K)) cur = bestRound;\n            else break;\n        }\n        return cur;\n    }\n\n    bool covers_need(const vector<int>& P, const vector<char>& need) const {\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (P[i] > 0) active.push_back(i);\n        for (int k = 0; k < K; k++) if (need[k]) {\n            bool ok = false;\n            for (int i : active) {\n                if (req[i][k] <= P[i]) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n        return true;\n    }\n\n    Candidate try_remove_station(const Candidate& cur, const vector<char>& allowed, int s) const {\n        Candidate best = cur;\n        if (cur.P[s] == 0) return best;\n\n        vector<int> active;\n        for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n\n        vector<char> need(K, 0);\n        int needCnt = 0;\n\n        for (int k = 0; k < K; k++) {\n            if (req[s][k] > cur.P[s]) continue;\n            bool other = false;\n            for (int i : active) {\n                if (i == s) continue;\n                if (req[i][k] <= cur.P[i]) {\n                    other = true;\n                    break;\n                }\n            }\n            if (!other) {\n                need[k] = 1;\n                needCnt++;\n            }\n        }\n\n        vector<int> baseP = cur.P;\n        baseP[s] = 0;\n\n        auto relax_from_P = [&](vector<int> P) {\n            if (elapsed() > HARD_LIMIT) return;\n            if (count_covered_by_P(P) < K) return;\n            reduce_powers(P);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate c = make_candidate(P, B);\n            if (better(c, best, K)) best = c;\n        };\n\n        if (needCnt == 0) {\n            relax_from_P(baseP);\n        } else {\n            vector<int> P1 = greedy_cover_subset(allowed, baseP, need, 1.0L, s);\n            if (covers_need(P1, need)) relax_from_P(P1);\n\n            if (elapsed() <= HARD_LIMIT && needCnt <= 2000) {\n                vector<int> P2 = greedy_cover_subset(allowed, baseP, need, 1.10L, s);\n                if (covers_need(P2, need)) relax_from_P(P2);\n            }\n        }\n\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P3 = greedy_on_allowed_gamma(allowed, 1.0L, s);\n            relax_from_P(P3);\n        }\n        if (elapsed() <= HARD_LIMIT) {\n            vector<int> P4 = greedy_on_allowed_gamma(allowed, 1.10L, s);\n            relax_from_P(P4);\n        }\n\n        return best;\n    }\n\n    Candidate local_remove(Candidate cur) const {\n        while (elapsed() < HARD_LIMIT) {\n            vector<int> active;\n            for (int i = 0; i < N; i++) if (cur.P[i] > 0) active.push_back(i);\n            if (active.empty()) break;\n\n            vector<char> allowed = tree_vertices(cur.B);\n\n            vector<int> deg(N, 0);\n            for (int e = 0; e < M; e++) if (cur.B[e]) {\n                deg[edges[e].u]++;\n                deg[edges[e].v]++;\n            }\n\n            vector<int> byPower = active;\n            sort(byPower.begin(), byPower.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> leafs;\n            for (int v : active) if (deg[v] == 1) leafs.push_back(v);\n            sort(leafs.begin(), leafs.end(), [&](int a, int b) {\n                long long ca = 1LL * cur.P[a] * cur.P[a];\n                long long cb = 1LL * cur.P[b] * cur.P[b];\n                if (ca != cb) return ca > cb;\n                return a < b;\n            });\n\n            vector<int> trials;\n            auto push_unique = [&](int v) {\n                for (int x : trials) if (x == v) return;\n                trials.push_back(v);\n            };\n\n            for (int i = 0; i < (int)leafs.size() && i < 6; i++) push_unique(leafs[i]);\n            for (int i = 0; i < (int)byPower.size() && i < 8; i++) push_unique(byPower[i]);\n\n            bool improved = false;\n            for (int s : trials) {\n                if (elapsed() > HARD_LIMIT) break;\n                Candidate cand = try_remove_station(cur, allowed, s);\n                if (better(cand, cur, K)) {\n                    cur = basic_improve(cand, 1);\n                    improved = true;\n                    break;\n                }\n            }\n            if (!improved) break;\n        }\n        return cur;\n    }\n\n    Candidate solve() {\n        Candidate best;\n\n        auto consider = [&](Candidate c, int rounds = 3) {\n            if (elapsed() > HARD_LIMIT) return;\n            c = basic_improve(c, rounds);\n            if (better(c, best, K)) best = c;\n        };\n\n        vector<pair<long double,long double>> connectedParams = {\n            {0.00L, 1.00L},\n            {0.20L, 1.00L},\n            {0.55L, 1.00L},\n            {1.00L, 1.00L},\n            {0.35L, 1.12L},\n        };\n\n        for (auto [alpha, gamma] : connectedParams) {\n            if (elapsed() > 0.98) break;\n            InitialState init = greedy_initial(alpha, gamma);\n            Candidate cand = make_candidate(init.P, init.B);\n            consider(cand, 3);\n        }\n\n        vector<char> allAllowed(N, 1);\n        vector<long double> globalGammas = {0.92L, 1.00L, 1.10L, 1.18L};\n\n        for (long double g : globalGammas) {\n            if (elapsed() > 1.42) break;\n            vector<int> P = greedy_on_allowed_gamma(allAllowed, g);\n            if (count_covered_by_P(P) < K) continue;\n            reduce_powers(P);\n            auto B = build_tree_best(terminals_from_P(P));\n            Candidate cand = make_candidate(P, B);\n            consider(cand, 3);\n        }\n\n        if (best.covered < 0) {\n            vector<int> P(N, 0);\n            vector<char> B(M, 0);\n            best = make_candidate(P, B);\n        }\n\n        if (elapsed() < 1.70) best = basic_improve(best, 2);\n        if (elapsed() < 1.82) best = local_remove(best);\n        if (elapsed() < HARD_LIMIT) best = basic_improve(best, 2);\n\n        return best;\n    }\n\n    void output(const Candidate& ans) const {\n        for (int i = 0; i < N; i++) {\n            if (i) cout << ' ';\n            cout << ans.P[i];\n        }\n        cout << '\\n';\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << int(ans.B[i]);\n        }\n        cout << '\\n';\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.input();\n    solver.precompute();\n    Candidate ans = solver.solve();\n    solver.output(ans);\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;\nusing ll = long long;\nusing Board = array<array<int, N>, N>;\nusing Perm = array<uint16_t, M>;\n\nstruct Op {\n    int x1, y1, x2, y2;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    int E = 0;\n\n    long long score_like() const {\n        if ((int)ops.size() > 10000) return -(1LL << 60);\n        if (E == 0) return 100000LL - 5LL * (int)ops.size();\n        return 50000LL - 50LL * E;\n    }\n};\n\nint desired_row[M];\nint noise_tbl[16][N][N];\nint pos_x[M], pos_y[M];\nvector<pair<int,int>> heap_edges;\nchrono::steady_clock::time_point g_start;\n\ndouble elapsed_ms() {\n    auto now = chrono::steady_clock::now();\n    return chrono::duration<double, milli>(now - g_start).count();\n}\n\nuint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed) : x(seed ? seed : 88172645463325252ULL) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int l, int r) {\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    bool next_bool() {\n        return (next() >> 63) & 1;\n    }\n};\n\ninline int vid(int x, int y) {\n    return x * (x + 1) / 2 + y;\n}\n\nvoid prepare_globals() {\n    int id = 0;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            pos_x[id] = x;\n            pos_y[id] = y;\n            ++id;\n        }\n    }\n\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            heap_edges.push_back({vid(x, y), vid(x + 1, y)});\n            heap_edges.push_back({vid(x, y), vid(x + 1, y + 1)});\n        }\n    }\n\n    for (int r = 0; r < N; ++r) {\n        int L = r * (r + 1) / 2;\n        int R = (r + 1) * (r + 2) / 2 - 1;\n        for (int v = L; v <= R && v < M; ++v) desired_row[v] = r;\n    }\n\n    for (int s = 0; s < 16; ++s) {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                uint64_t h = splitmix64(123456789ULL + 1000003ULL * s + 1009ULL * x + y);\n                noise_tbl[s][x][y] = (int)(h % 19) - 9;\n            }\n        }\n    }\n}\n\nint count_violations(const Board& a) {\n    int E = 0;\n    for (int x = 0; x < N - 1; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            if (a[x][y] > a[x + 1][y]) ++E;\n            if (a[x][y] > a[x + 1][y + 1]) ++E;\n        }\n    }\n    return E;\n}\n\nBoard reflect_board(const Board& a) {\n    Board b{};\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            b[x][y] = a[x][x - y];\n        }\n    }\n    return b;\n}\n\nvector<Op> reflect_ops(vector<Op> ops) {\n    for (auto& op : ops) {\n        op.y1 = op.x1 - op.y1;\n        op.y2 = op.x2 - op.y2;\n    }\n    return ops;\n}\n\nbool better_candidate(const Candidate& a, const Candidate& b) {\n    if (a.score_like() != b.score_like()) return a.score_like() > b.score_like();\n    if (a.E != b.E) return a.E < b.E;\n    return a.ops.size() < b.ops.size();\n}\n\nvoid apply_ops(Board& b, const vector<Op>& ops) {\n    for (const auto& op : ops) {\n        swap(b[op.x1][op.y1], b[op.x2][op.y2]);\n    }\n}\n\nstruct COp {\n    Op op;\n    int a, b;\n};\n\ninline bool same_edge(const COp& p, const COp& q) {\n    return p.a == q.a && p.b == q.b;\n}\ninline bool disjoint_edges(const COp& p, const COp& q) {\n    return p.a != q.a && p.a != q.b && p.b != q.a && p.b != q.b;\n}\n\nvector<Op> compress_once(const vector<Op>& ops) {\n    vector<COp> st;\n    st.reserve(ops.size());\n    for (const auto& op : ops) {\n        int u = vid(op.x1, op.y1);\n        int v = vid(op.x2, op.y2);\n        if (u > v) swap(u, v);\n        st.push_back({op, u, v});\n        int i = (int)st.size() - 1;\n        while (i > 0) {\n            if (same_edge(st[i], st[i - 1])) {\n                st.erase(st.begin() + i - 1, st.begin() + i + 1);\n                break;\n            }\n            if (disjoint_edges(st[i], st[i - 1])) {\n                swap(st[i], st[i - 1]);\n                --i;\n            } else {\n                break;\n            }\n        }\n    }\n    vector<Op> res;\n    res.reserve(st.size());\n    for (auto& e : st) res.push_back(e.op);\n    return res;\n}\n\nvector<Op> compress_ops(vector<Op> ops) {\n    while (true) {\n        size_t before = ops.size();\n        ops = compress_once(ops);\n        if (ops.size() == before) break;\n    }\n    return ops;\n}\n\nCandidate normalize_candidate(const Board& init, Candidate c) {\n    c.ops = compress_ops(std::move(c.ops));\n    Board b = init;\n    apply_ops(b, c.ops);\n    c.E = count_violations(b);\n    return c;\n}\n\n/* ---------------- fast pruning ---------------- */\n\nvoid build_perms(const vector<Op>& ops, vector<Perm>& pref, vector<Perm>& suf) {\n    int K = (int)ops.size();\n    pref.resize(K + 1);\n    suf.resize(K + 1);\n\n    for (int p = 0; p < M; ++p) pref[0][p] = (uint16_t)p;\n    for (int i = 0; i < K; ++i) {\n        pref[i + 1] = pref[i];\n        int u = vid(ops[i].x1, ops[i].y1);\n        int v = vid(ops[i].x2, ops[i].y2);\n        swap(pref[i + 1][u], pref[i + 1][v]);\n    }\n\n    for (int p = 0; p < M; ++p) suf[K][p] = (uint16_t)p;\n    for (int i = K - 1; i >= 0; --i) {\n        suf[i] = suf[i + 1];\n        int u = vid(ops[i].x1, ops[i].y1);\n        int v = vid(ops[i].x2, ops[i].y2);\n        for (int p = 0; p < M; ++p) {\n            if (suf[i][p] == u) suf[i][p] = (uint16_t)v;\n            else if (suf[i][p] == v) suf[i][p] = (uint16_t)u;\n        }\n    }\n}\n\nbool valid_skip_segment_fast(\n    const vector<Perm>& pref,\n    const vector<Perm>& suf,\n    int l, int r,\n    const array<int, M>& init_flat\n) {\n    const Perm& P = pref[l];\n    const Perm& S = suf[r];\n    for (auto [par, chi] : heap_edges) {\n        int vp = init_flat[P[S[par]]];\n        int vc = init_flat[P[S[chi]]];\n        if (vp > vc) return false;\n    }\n    return true;\n}\n\nCandidate prune_candidate_fast(const array<int, M>& init_flat, Candidate cand, double limit_ms, uint64_t seed) {\n    if (cand.E != 0) return cand;\n    cand.ops = compress_ops(std::move(cand.ops));\n    XorShift64 rng(seed ^ 0x3141592653589793ULL ^ (uint64_t)cand.ops.size());\n\n    vector<Perm> pref, suf;\n\n    auto try_scan = [&](int bs, int offset, bool reverse_dir) -> bool {\n        build_perms(cand.ops, pref, suf);\n        bool changed = false;\n        int K = (int)cand.ops.size();\n        if (K == 0) return false;\n\n        vector<pair<int,int>> segs;\n        segs.reserve((K + bs - 1) / bs + 2);\n        for (int l = offset; l < K; l += bs) {\n            int r = min(l + bs, K);\n            if (l < r) segs.push_back({l, r});\n        }\n        if (reverse_dir) reverse(segs.begin(), segs.end());\n\n        for (auto [l, r] : segs) {\n            if (elapsed_ms() > limit_ms) break;\n            if (valid_skip_segment_fast(pref, suf, l, r, init_flat)) {\n                cand.ops.erase(cand.ops.begin() + l, cand.ops.begin() + r);\n                changed = true;\n                break;\n            }\n        }\n        return changed;\n    };\n\n    auto try_random = [&](int bs, int trials) -> bool {\n        int K = (int)cand.ops.size();\n        if (K == 0) return false;\n        bs = min(bs, K);\n\n        build_perms(cand.ops, pref, suf);\n        for (int t = 0; t < trials && elapsed_ms() <= limit_ms; ++t) {\n            int len = bs;\n            if (bs >= 8) {\n                int delta = max(1, bs / 4);\n                int lo = max(1, bs - delta);\n                int hi = min(K, bs + delta);\n                len = rng.next_int(lo, hi);\n            }\n            if (len > K) len = K;\n            int l = rng.next_int(0, K - len);\n            int r = l + len;\n            if (valid_skip_segment_fast(pref, suf, l, r, init_flat)) {\n                cand.ops.erase(cand.ops.begin() + l, cand.ops.begin() + r);\n                return true;\n            }\n        }\n        return false;\n    };\n\n    static const int BS[] = {256, 192, 128, 96, 64, 48, 32, 24, 16, 12, 8, 6, 4, 3, 2, 1};\n\n    for (int round = 0; round < 3 && elapsed_ms() <= limit_ms; ++round) {\n        for (int bs : BS) {\n            if (elapsed_ms() > limit_ms) break;\n            bool any = false;\n            while (elapsed_ms() <= limit_ms) {\n                bool changed = false;\n                changed |= try_scan(bs, 0, false);\n                if (!changed && bs >= 4) changed |= try_scan(bs, bs / 2, false);\n                if (!changed) changed |= try_scan(bs, 0, true);\n                if (!changed && bs >= 4) changed |= try_scan(bs, bs / 2, true);\n                if (!changed && bs >= 8) changed |= try_random(bs, 6);\n                if (!changed) break;\n                any = true;\n            }\n            if (any) cand.ops = compress_ops(std::move(cand.ops));\n        }\n    }\n\n    vector<Perm> pref2, suf2;\n    build_perms(cand.ops, pref2, suf2);\n    const Perm& P = pref2[(int)cand.ops.size()];\n    array<int, M> fin{};\n    for (int p = 0; p < M; ++p) fin[p] = init_flat[P[p]];\n    int E = 0;\n    for (auto [par, chi] : heap_edges) if (fin[par] > fin[chi]) ++E;\n    cand.E = E;\n\n    return cand;\n}\n\n/* ---------------- fallback constructive family ---------------- */\n\nstruct Builder {\n    Board a;\n    vector<Op> ops;\n\n    Builder(const Board& init) : a(init) {\n        ops.reserve(10000);\n    }\n\n    static bool reachable_down(int r, int c, int tr, int tc) {\n        if (r > tr) return false;\n        return (c <= tc && tc <= c + (tr - r));\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        swap(a[x1][y1], a[x2][y2]);\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    pair<int,int> find_min_subtriangle(int x, int y) const {\n        int best_v = INT_MAX;\n        pair<int,int> best = {x, y};\n        for (int i = x; i < N; ++i) {\n            int l = y;\n            int r = y + (i - x);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] < best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    pair<int,int> find_max_uppertriangle(int x, int y) const {\n        int best_v = -1;\n        pair<int,int> best = {x, y};\n        for (int i = 0; i <= x; ++i) {\n            int l = max(0, y - (x - i));\n            int r = min(i, y);\n            for (int j = l; j <= r; ++j) {\n                if (a[i][j] > best_v) {\n                    best_v = a[i][j];\n                    best = {i, j};\n                }\n            }\n        }\n        return best;\n    }\n\n    vector<pair<int,int>> build_best_path_top(int tx, int ty, int sx, int sy) const {\n        const int NEG = -1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) dp[i][j] = NEG;\n\n        dp[sx][sy] = 0;\n        for (int r = sx - 1; r >= tx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, sx, sy)) continue;\n                int best = NEG;\n                if (reachable_down(r + 1, c, sx, sy) && dp[r + 1][c] != NEG)\n                    best = max(best, dp[r + 1][c]);\n                if (reachable_down(r + 1, c + 1, sx, sy) && dp[r + 1][c + 1] != NEG)\n                    best = max(best, dp[r + 1][c + 1]);\n                if (best != NEG) dp[r][c] = a[r][c] + best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = tx, c = ty;\n        path.push_back({r, c});\n        while (!(r == sx && c == sy)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = NEG;\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, sx, sy)) return;\n                if (dp[nr][nc] == NEG) return;\n                if (nxt.first == -1 || dp[nr][nc] > best ||\n                    (dp[nr][nc] == best && a[nr][nc] > a[nxt.first][nxt.second])) {\n                    best = dp[nr][nc];\n                    nxt = {nr, nc};\n                }\n            };\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back({r, c});\n        }\n        return path;\n    }\n\n    vector<pair<int,int>> build_best_path_bottom(int sx, int sy, int tx, int ty) const {\n        const int INF = 1e9;\n        int dp[N][N];\n        for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) dp[i][j] = INF;\n\n        dp[tx][ty] = 0;\n        for (int r = tx - 1; r >= sx; --r) {\n            for (int c = 0; c <= r; ++c) {\n                if (!reachable_down(r, c, tx, ty)) continue;\n                int best = INF;\n                if (reachable_down(r + 1, c, tx, ty) && dp[r + 1][c] != INF)\n                    best = min(best, a[r + 1][c] + dp[r + 1][c]);\n                if (reachable_down(r + 1, c + 1, tx, ty) && dp[r + 1][c + 1] != INF)\n                    best = min(best, a[r + 1][c + 1] + dp[r + 1][c + 1]);\n                dp[r][c] = best;\n            }\n        }\n\n        vector<pair<int,int>> path;\n        int r = sx, c = sy;\n        path.push_back({r, c});\n        while (!(r == tx && c == ty)) {\n            pair<int,int> nxt = {-1, -1};\n            int best = INF;\n            auto consider = [&](int nr, int nc) {\n                if (!reachable_down(nr, nc, tx, ty)) return;\n                if (dp[nr][nc] == INF) return;\n                int cand = a[nr][nc] + dp[nr][nc];\n                if (nxt.first == -1 || cand < best ||\n                    (cand == best && a[nr][nc] < a[nxt.first][nxt.second])) {\n                    best = cand;\n                    nxt = {nr, nc};\n                }\n            };\n            consider(r + 1, c);\n            consider(r + 1, c + 1);\n            r = nxt.first;\n            c = nxt.second;\n            path.push_back({r, c});\n        }\n        return path;\n    }\n\n    Candidate solve_topdown() {\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_min_subtriangle(x, y);\n                auto path = build_best_path_top(x, y, sx, sy);\n                for (int i = (int)path.size() - 1; i >= 1; --i) {\n                    auto [x1, y1] = path[i];\n                    auto [x2, y2] = path[i - 1];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n\n    Candidate solve_bottomup() {\n        for (int x = N - 1; x >= 0; --x) {\n            for (int y = 0; y <= x; ++y) {\n                auto [sx, sy] = find_max_uppertriangle(x, y);\n                auto path = build_best_path_bottom(sx, sy, x, y);\n                for (int i = 1; i < (int)path.size(); ++i) {\n                    auto [x1, y1] = path[i - 1];\n                    auto [x2, y2] = path[i];\n                    do_swap(x1, y1, x2, y2);\n                    if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n                }\n            }\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\nCandidate solve_builder_top(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_topdown();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nCandidate solve_builder_bottom(const Board& init, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    Builder builder(b);\n    Candidate c = builder.solve_bottomup();\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\n/* ---------------- monotone range-based family ---------------- */\n\nstruct ValueParams {\n    ll W;\n    ll coef_value;\n    ll coef_mis;\n    int noise_id;\n};\n\nenum class Policy {\n    PURE_LOW,\n    PURE_HIGH,\n    GREEDY_LEN,\n    GREEDY_OBJ,\n    ALT_LOW,\n    ALT_HIGH\n};\n\nstruct PathInfo {\n    vector<pair<int,int>> path;\n    int len = (int)1e9;\n    ll obj = (1LL << 60);\n    bool valid = false;\n};\n\nstruct RangeSolver {\n    Board a;\n    array<int, M> posx{}, posy{};\n    vector<Op> ops;\n    ValueParams prm;\n\n    int lo = 0, hi = M - 1;\n    int curv = 0;\n\n    static constexpr ll INF = (1LL << 60);\n\n    ll memo[N][N];\n    bool seen[N][N];\n    int nxtx[N][N], nxty[N][N];\n\n    RangeSolver(const Board& init, ValueParams p) : a(init), prm(p) {\n        ops.reserve(10000);\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y <= x; ++y) {\n                int v = a[x][y];\n                posx[v] = x;\n                posy[v] = y;\n            }\n        }\n    }\n\n    inline ll noise_at(int x, int y) const {\n        if (prm.noise_id < 0) return 0;\n        return noise_tbl[prm.noise_id][x][y];\n    }\n\n    inline ll reward_up(int px, int py) const {\n        int t = a[px][py];\n        int before = abs(px - desired_row[t]);\n        int after = abs((px + 1) - desired_row[t]);\n        int delta = after - before;\n        return prm.coef_value * t - prm.coef_mis * delta + noise_at(px, py);\n    }\n\n    inline ll penalty_down(int cx, int cy) const {\n        int t = a[cx][cy];\n        int before = abs(cx - desired_row[t]);\n        int after = abs((cx - 1) - desired_row[t]);\n        int delta = after - before;\n        return prm.coef_value * t + prm.coef_mis * delta + noise_at(cx, cy);\n    }\n\n    void do_swap(int x1, int y1, int x2, int y2) {\n        int v1 = a[x1][y1];\n        int v2 = a[x2][y2];\n        swap(a[x1][y1], a[x2][y2]);\n        posx[v1] = x2; posy[v1] = y2;\n        posx[v2] = x1; posy[v2] = y1;\n        ops.push_back({x1, y1, x2, y2});\n    }\n\n    bool goal_up(int x, int y) const {\n        if (x == 0) return true;\n        if (y > 0 && a[x - 1][y - 1] >= lo) return false;\n        if (y < x && a[x - 1][y] >= lo) return false;\n        return true;\n    }\n\n    bool goal_down(int x, int y) const {\n        if (x == N - 1) return true;\n        if (a[x + 1][y] <= hi) return false;\n        if (a[x + 1][y + 1] <= hi) return false;\n        return true;\n    }\n\n    ll dfs_up(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        ll bestReward = -(1LL << 60);\n\n        auto consider = [&](int px, int py) {\n            int t = a[px][py];\n            if (!(lo < t && t <= hi)) return;\n            ll sub = dfs_up(px, py);\n            if (sub >= INF / 4) return;\n            ll rew = reward_up(px, py);\n            ll cand = sub + prm.W - rew;\n            if (cand < best || (cand == best && (rew > bestReward ||\n                (rew == bestReward && py < by)))) {\n                best = cand;\n                bx = px; by = py;\n                bestReward = rew;\n            }\n        };\n\n        if (x > 0) {\n            if (y > 0) consider(x - 1, y - 1);\n            if (y < x) consider(x - 1, y);\n        }\n\n        if (goal_up(x, y)) {\n            if (0 < best || bx == -1) {\n                best = 0;\n                bx = by = -1;\n            }\n        }\n\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    ll dfs_down(int x, int y) {\n        if (seen[x][y]) return memo[x][y];\n        seen[x][y] = true;\n\n        ll best = INF;\n        int bx = -1, by = -1;\n        ll bestPen = (1LL << 60);\n\n        auto consider = [&](int cx, int cy) {\n            int t = a[cx][cy];\n            if (!(lo <= t && t < hi)) return;\n            ll sub = dfs_down(cx, cy);\n            if (sub >= INF / 4) return;\n            ll pen = penalty_down(cx, cy);\n            ll cand = sub + prm.W + pen;\n            if (cand < best || (cand == best && (pen < bestPen ||\n                (pen == bestPen && cy < by)))) {\n                best = cand;\n                bx = cx; by = cy;\n                bestPen = pen;\n            }\n        };\n\n        if (x + 1 < N) {\n            consider(x + 1, y);\n            consider(x + 1, y + 1);\n        }\n\n        if (goal_down(x, y)) {\n            if (0 < best || bx == -1) {\n                best = 0;\n                bx = by = -1;\n            }\n        }\n\n        memo[x][y] = best;\n        nxtx[x][y] = bx;\n        nxty[x][y] = by;\n        return best;\n    }\n\n    PathInfo get_low_path(int lo_, int hi_) {\n        lo = lo_;\n        hi = hi_;\n        curv = lo;\n        memset(seen, 0, sizeof(seen));\n        int x = posx[curv], y = posy[curv];\n        ll obj = dfs_up(x, y);\n\n        PathInfo res;\n        if (obj >= INF / 4) return res;\n        res.valid = true;\n        res.obj = obj;\n        res.path.push_back({x, y});\n        while (nxtx[x][y] != -1) {\n            int nx = nxtx[x][y], ny = nxty[x][y];\n            res.path.push_back({nx, ny});\n            x = nx; y = ny;\n        }\n        res.len = (int)res.path.size() - 1;\n        return res;\n    }\n\n    PathInfo get_high_path(int lo_, int hi_) {\n        lo = lo_;\n        hi = hi_;\n        curv = hi;\n        memset(seen, 0, sizeof(seen));\n        int x = posx[curv], y = posy[curv];\n        ll obj = dfs_down(x, y);\n\n        PathInfo res;\n        if (obj >= INF / 4) return res;\n        res.valid = true;\n        res.obj = obj;\n        res.path.push_back({x, y});\n        while (nxtx[x][y] != -1) {\n            int nx = nxtx[x][y], ny = nxty[x][y];\n            res.path.push_back({nx, ny});\n            x = nx; y = ny;\n        }\n        res.len = (int)res.path.size() - 1;\n        return res;\n    }\n\n    void apply_path(const vector<pair<int,int>>& path) {\n        for (int i = 0; i + 1 < (int)path.size(); ++i) {\n            auto [x1, y1] = path[i];\n            auto [x2, y2] = path[i + 1];\n            do_swap(x1, y1, x2, y2);\n        }\n    }\n\n    Candidate run(Policy policy) {\n        int l = 0, h = M - 1;\n        bool alt_take_low = (policy == Policy::ALT_LOW);\n\n        while (l <= h) {\n            if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n            bool take_low = false;\n\n            if (policy == Policy::PURE_LOW) {\n                take_low = true;\n            } else if (policy == Policy::PURE_HIGH) {\n                take_low = false;\n            } else if (policy == Policy::ALT_LOW || policy == Policy::ALT_HIGH) {\n                take_low = alt_take_low;\n            } else {\n                PathInfo up = get_low_path(l, h);\n                PathInfo dn = get_high_path(l, h);\n\n                if (!up.valid && !dn.valid) {\n                    return Candidate{ops, count_violations(a)};\n                } else if (!up.valid) {\n                    take_low = false;\n                } else if (!dn.valid) {\n                    take_low = true;\n                } else if (policy == Policy::GREEDY_LEN) {\n                    if (up.len != dn.len) take_low = up.len < dn.len;\n                    else if (up.obj != dn.obj) take_low = up.obj < dn.obj;\n                    else take_low = true;\n                } else {\n                    if (up.obj != dn.obj) take_low = up.obj < dn.obj;\n                    else if (up.len != dn.len) take_low = up.len < dn.len;\n                    else take_low = true;\n                }\n\n                if (take_low) {\n                    apply_path(up.path);\n                    ++l;\n                } else {\n                    apply_path(dn.path);\n                    --h;\n                }\n\n                if (policy == Policy::ALT_LOW || policy == Policy::ALT_HIGH) {\n                    alt_take_low = !alt_take_low;\n                }\n                continue;\n            }\n\n            if (take_low) {\n                PathInfo up = get_low_path(l, h);\n                if (!up.valid) return Candidate{ops, count_violations(a)};\n                apply_path(up.path);\n                ++l;\n            } else {\n                PathInfo dn = get_high_path(l, h);\n                if (!dn.valid) return Candidate{ops, count_violations(a)};\n                apply_path(dn.path);\n                --h;\n            }\n\n            if (policy == Policy::ALT_LOW || policy == Policy::ALT_HIGH) {\n                alt_take_low = !alt_take_low;\n            }\n        }\n\n        return Candidate{ops, count_violations(a)};\n    }\n\n    Candidate run_switch_once(int first_cnt, bool low_then_high) {\n        int l = 0, h = M - 1;\n        int done = 0;\n        while (l <= h) {\n            if ((int)ops.size() > 10000) return Candidate{ops, count_violations(a)};\n            bool take_low = low_then_high ? (done < first_cnt) : !(done < first_cnt);\n            if (take_low) {\n                PathInfo up = get_low_path(l, h);\n                if (!up.valid) return Candidate{ops, count_violations(a)};\n                apply_path(up.path);\n                ++l;\n            } else {\n                PathInfo dn = get_high_path(l, h);\n                if (!dn.valid) return Candidate{ops, count_violations(a)};\n                apply_path(dn.path);\n                --h;\n            }\n            ++done;\n        }\n        return Candidate{ops, count_violations(a)};\n    }\n};\n\nCandidate solve_range(const Board& init, ValueParams prm, Policy policy, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    RangeSolver solver(b, prm);\n    Candidate c = solver.run(policy);\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\nCandidate solve_switch_once(const Board& init, ValueParams prm, int first_cnt, bool low_then_high, bool refl) {\n    Board b = refl ? reflect_board(init) : init;\n    RangeSolver solver(b, prm);\n    Candidate c = solver.run_switch_once(first_cnt, low_then_high);\n    if (refl) c.ops = reflect_ops(std::move(c.ops));\n    return c;\n}\n\n/* ---------------- main ---------------- */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    prepare_globals();\n\n    Board init{};\n    array<int, M> init_flat{};\n    uint64_t seed = 0;\n    int idx = 0;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y <= x; ++y) {\n            cin >> init[x][y];\n            init_flat[idx++] = init[x][y];\n            seed = splitmix64(seed ^ (uint64_t)(init[x][y] + 1009 * x + 65537 * y + 1));\n        }\n    }\n\n    g_start = chrono::steady_clock::now();\n\n    Candidate best = normalize_candidate(init, Candidate{{}, count_violations(init)});\n    vector<Candidate> pool;\n\n    auto add_pool = [&](const Candidate& c) {\n        if (c.E != 0 || (int)c.ops.size() > 10000) return;\n        pool.push_back(c);\n        sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.ops.size() != b.ops.size()) return a.ops.size() < b.ops.size();\n            return a.score_like() > b.score_like();\n        });\n        if ((int)pool.size() > 20) pool.pop_back();\n    };\n\n    auto consider = [&](Candidate cand) {\n        if ((int)cand.ops.size() > 10000) return;\n        if (best.E == 0 && cand.E == 0 && !best.ops.empty()) {\n            if ((int)cand.ops.size() >= (int)best.ops.size() + 100) return;\n        }\n        cand = normalize_candidate(init, std::move(cand));\n        add_pool(cand);\n        if (better_candidate(cand, best)) best = cand;\n    };\n\n    vector<ValueParams> params = {\n        {1000000000LL, 0,  0,  -1},\n        {950LL,        1,  0,  -1},\n        {850LL,        1,  0,  -1},\n        {750LL,        1,  4,  -1},\n        {650LL,        1,  8,  -1},\n        {550LL,        1, 12,  -1},\n        {450LL,        1, 16,  -1},\n        {380LL,        1, 20,  -1},\n        {320LL,        1, 24,  -1},\n        {280LL,        2, 16,  -1},\n        {450LL,        1, 16,   0},\n        {380LL,        1, 20,   1},\n        {320LL,        1, 24,   2},\n        {280LL,        2, 16,   3},\n    };\n\n    for (const auto& prm : params) {\n        for (bool refl : {false, true}) {\n            if (elapsed_ms() > 1000.0) break;\n            consider(solve_range(init, prm, Policy::PURE_LOW, refl));\n            if (elapsed_ms() > 1050.0) break;\n            consider(solve_range(init, prm, Policy::PURE_HIGH, refl));\n            if (elapsed_ms() > 1100.0) break;\n            consider(solve_range(init, prm, Policy::GREEDY_LEN, refl));\n            if (elapsed_ms() > 1150.0) break;\n            consider(solve_range(init, prm, Policy::GREEDY_OBJ, refl));\n        }\n        if (elapsed_ms() > 1200.0) break;\n    }\n\n    if (elapsed_ms() <= 1280.0) {\n        for (bool refl : {false, true}) {\n            consider(solve_range(init, {450LL, 1, 16, -1}, Policy::ALT_LOW, refl));\n            consider(solve_range(init, {450LL, 1, 16, -1}, Policy::ALT_HIGH, refl));\n            consider(solve_range(init, {320LL, 1, 24, 2}, Policy::ALT_LOW, refl));\n            consider(solve_range(init, {320LL, 1, 24, 2}, Policy::ALT_HIGH, refl));\n        }\n    }\n\n    // New switch-once family.\n    if (elapsed_ms() <= 1450.0) {\n        vector<int> switch_counts = {15, 78, 171, 300};\n        vector<ValueParams> switch_params = {\n            {450LL, 1, 16, -1},\n            {320LL, 1, 24,  2},\n        };\n        for (const auto& prm : switch_params) {\n            for (int cnt : switch_counts) {\n                for (bool refl : {false, true}) {\n                    if (elapsed_ms() > 1600.0) break;\n                    consider(solve_switch_once(init, prm, cnt, true, refl));   // low then high\n                    if (elapsed_ms() > 1650.0) break;\n                    consider(solve_switch_once(init, prm, cnt, false, refl));  // high then low\n                }\n            }\n        }\n    }\n\n    if (elapsed_ms() <= 1680.0) consider(solve_builder_top(init, false));\n    if (elapsed_ms() <= 1710.0) consider(solve_builder_top(init, true));\n    if (elapsed_ms() <= 1740.0) consider(solve_builder_bottom(init, false));\n    if (elapsed_ms() <= 1770.0) consider(solve_builder_bottom(init, true));\n\n    XorShift64 rng(seed ^ 0x9e3779b97f4a7c15ULL);\n\n    static const ll Wlist[] = {\n        1000000000LL, 1000LL, 950LL, 900LL, 850LL, 800LL, 750LL,\n        700LL, 650LL, 600LL, 550LL, 500LL, 450LL, 420LL, 380LL,\n        350LL, 320LL, 300LL, 280LL, 260LL\n    };\n    static const ll CVlist[] = {0LL, 1LL, 1LL, 1LL, 2LL};\n    static const ll CMlist[] = {0LL, 4LL, 8LL, 12LL, 16LL, 20LL, 24LL, 28LL};\n    vector<Policy> rand_policies = {\n        Policy::PURE_LOW, Policy::PURE_LOW,\n        Policy::PURE_HIGH, Policy::PURE_HIGH,\n        Policy::GREEDY_LEN, Policy::GREEDY_LEN,\n        Policy::GREEDY_OBJ, Policy::GREEDY_OBJ,\n        Policy::ALT_LOW, Policy::ALT_HIGH\n    };\n    vector<int> rand_switch_counts = {15, 36, 78, 120, 171, 231, 300, 378};\n\n    while (elapsed_ms() < 1810.0) {\n        ValueParams prm;\n        prm.W = Wlist[rng.next_int(0, (int)(sizeof(Wlist) / sizeof(Wlist[0])) - 1)];\n        prm.coef_value = CVlist[rng.next_int(0, (int)(sizeof(CVlist) / sizeof(CVlist[0])) - 1)];\n        prm.coef_mis = CMlist[rng.next_int(0, (int)(sizeof(CMlist) / sizeof(CMlist[0])) - 1)];\n        int z = rng.next_int(0, 19);\n        prm.noise_id = (z < 4 ? -1 : z - 4);\n\n        bool refl = rng.next_bool();\n        if ((rng.next() & 7ULL) == 0ULL) {\n            int cnt = rand_switch_counts[rng.next_int(0, (int)rand_switch_counts.size() - 1)];\n            bool low_then_high = rng.next_bool();\n            consider(solve_switch_once(init, prm, cnt, low_then_high, refl));\n        } else {\n            Policy pol = rand_policies[rng.next_int(0, (int)rand_policies.size() - 1)];\n            consider(solve_range(init, prm, pol, refl));\n        }\n    }\n\n    add_pool(best);\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.ops.size() != b.ops.size()) return a.ops.size() < b.ops.size();\n        return a.score_like() > b.score_like();\n    });\n\n    for (int i = 0; i < (int)pool.size() && elapsed_ms() < 1940.0; ++i) {\n        Candidate pruned = prune_candidate_fast(init_flat, pool[i], 1940.0, seed ^ (uint64_t)i * 1000003ULL);\n        pruned = normalize_candidate(init, std::move(pruned));\n        if (better_candidate(pruned, best)) best = std::move(pruned);\n    }\n\n    if (best.E == 0 && elapsed_ms() < 1988.0) {\n        Candidate pruned_best = prune_candidate_fast(init_flat, best, 1988.0, seed ^ 0xabcdef1234567890ULL);\n        pruned_best = normalize_candidate(init, std::move(pruned_best));\n        if (better_candidate(pruned_best, best)) best = std::move(pruned_best);\n    }\n\n    if ((int)best.ops.size() > 10000) {\n        best.ops.clear();\n    }\n\n    cout << best.ops.size() << '\\n';\n    for (const auto& op : best.ops) {\n        cout << op.x1 << ' ' << op.y1 << ' ' << op.x2 << ' ' << op.y2 << '\\n';\n    }\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Fenwick {\n    int n;\n    vector<int> bit;\n    Fenwick() : n(0) {}\n    Fenwick(int n_) { init(n_); }\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n    }\n    void add(int idx, int val) {\n        for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sumPrefix(int r) const { // [0, r)\n        int s = 0;\n        for (; r > 0; r -= r & -r) s += bit[r];\n        return s;\n    }\n    int total() const { return sumPrefix(n); }\n};\n\nstruct Strategy {\n    int hmode; // 0,1,2\n    int smode; // 0,1\n};\n\nstruct PeelInfo {\n    array<int, 81> pos;\n    vector<int> safe0;\n};\n\nclass Solver {\n    static constexpr int V = 81;\n    static constexpr int H = 3;\n    static constexpr int LATE_REM = 24;\n\n    int D, N, M;\n    int root;\n\n    array<char, V> obstacle{};\n    array<vector<int>, V> adj;\n    array<int, V> dist0{};\n    vector<int> cells;\n    array<int, V> label{};\n\n    Strategy best_strategy{0, 0};\n\n    int id(int i, int j) const { return i * D + j; }\n\n    void build_adj() {\n        for (int v = 0; v < V; ++v) adj[v].clear();\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n        for (int i = 0; i < D; ++i) {\n            for (int j = 0; j < D; ++j) {\n                int u = id(i, j);\n                if (obstacle[u]) continue;\n                for (int dir = 0; dir < 4; ++dir) {\n                    int ni = i + di[dir], nj = j + dj[dir];\n                    if (ni < 0 || ni >= D || nj < 0 || nj >= D) continue;\n                    int v = id(ni, nj);\n                    if (obstacle[v]) continue;\n                    adj[u].push_back(v);\n                }\n            }\n        }\n    }\n\n    void bfs_dist(const array<char, V>& active, array<int, V>& dist) const {\n        dist.fill(-1);\n        if (!active[root]) return;\n        queue<int> q;\n        q.push(root);\n        dist[root] = 0;\n        while (!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for (int v : adj[u]) {\n                if (!active[v] || dist[v] != -1) continue;\n                dist[v] = dist[u] + 1;\n                q.push(v);\n            }\n        }\n    }\n\n    void dfs_art(\n        int u, int p,\n        const array<char, V>& active,\n        array<int, V>& ord,\n        array<int, V>& low,\n        array<char, V>& arti,\n        int& timer\n    ) const {\n        ord[u] = low[u] = timer++;\n        int child = 0;\n        for (int v : adj[u]) {\n            if (!active[v]) continue;\n            if (ord[v] == -1) {\n                ++child;\n                dfs_art(v, u, active, ord, low, arti, timer);\n                low[u] = min(low[u], low[v]);\n                if (p != -1 && low[v] >= ord[u]) arti[u] = 1;\n            } else if (v != p) {\n                low[u] = min(low[u], ord[v]);\n            }\n        }\n        if (p == -1 && child > 1) arti[u] = 1;\n    }\n\n    void compute_articulation(const array<char, V>& active, array<char, V>& arti) const {\n        arti.fill(0);\n        array<int, V> ord, low;\n        ord.fill(-1);\n        low.fill(-1);\n        int timer = 0;\n        if (active[root]) dfs_art(root, -1, active, ord, low, arti, timer);\n    }\n\n    array<int, 4> make_key(\n        int v,\n        const array<int, V>& dist,\n        const array<int, V>& deg,\n        int hmode\n    ) const {\n        if (hmode == 0) {\n            return {dist[v], -deg[v], dist0[v], -v};\n        } else if (hmode == 1) {\n            return {dist0[v], -deg[v], dist[v], -v};\n        } else {\n            return {2 * dist[v] + dist0[v], -deg[v], dist[v], -v};\n        }\n    }\n\n    PeelInfo peel_info(const array<char, V>& occupied, int hmode) const {\n        PeelInfo info;\n        info.pos.fill(-1);\n        info.safe0.clear();\n\n        array<char, V> active{};\n        active.fill(0);\n        active[root] = 1;\n        int rem = 0;\n        for (int v : cells) {\n            if (!occupied[v]) {\n                active[v] = 1;\n                ++rem;\n            }\n        }\n\n        for (int step = 0; step < rem; ++step) {\n            array<int, V> dist;\n            bfs_dist(active, dist);\n\n            array<char, V> arti;\n            compute_articulation(active, arti);\n\n            array<int, V> deg{};\n            deg.fill(0);\n            for (int u = 0; u < V; ++u) {\n                if (!active[u]) continue;\n                for (int v : adj[u]) if (active[v]) ++deg[u];\n            }\n\n            vector<int> safe;\n            int best = -1;\n            array<int, 4> bestKey{};\n\n            for (int v : cells) {\n                if (!active[v]) continue;\n                if (dist[v] == -1) continue;\n                if (arti[v]) continue;\n                safe.push_back(v);\n                auto key = make_key(v, dist, deg, hmode);\n                if (best == -1 || key > bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n\n            if (step == 0) info.safe0 = safe;\n\n            if (best == -1) {\n                for (int v : cells) {\n                    if (active[v] && dist[v] != -1) {\n                        best = v;\n                        break;\n                    }\n                }\n                if (step == 0 && info.safe0.empty() && best != -1) {\n                    info.safe0.push_back(best);\n                }\n            }\n\n            if (best == -1) break;\n            info.pos[best] = step;\n            active[best] = 0;\n        }\n\n        return info;\n    }\n\n    int choose_cell_base(const array<char, V>& occupied, const Fenwick& unseen, int t, const Strategy& st) const {\n        int m = unseen.total();\n        int r = unseen.sumPrefix(t);\n\n        PeelInfo info = peel_info(occupied, st.hmode);\n        vector<int> safe = info.safe0;\n\n        if (safe.empty()) {\n            for (int v : cells) if (!occupied[v]) return v;\n            return cells.front();\n        }\n\n        if (st.smode == 0) {\n            sort(safe.begin(), safe.end(), [&](int a, int b) {\n                if (info.pos[a] != info.pos[b]) return info.pos[a] > info.pos[b];\n                return a < b;\n            });\n            int idx = (int)((long long)r * (int)safe.size() / m);\n            if (idx >= (int)safe.size()) idx = (int)safe.size() - 1;\n            return safe[idx];\n        } else {\n            int target = m - 1 - r;\n            int best = -1;\n            pair<int, int> bestPair{INT_MAX, INT_MAX};\n            for (int v : safe) {\n                int d = abs(info.pos[v] - target);\n                int tie = (target * 2 >= m - 1) ? -info.pos[v] : info.pos[v];\n                pair<int, int> cur{d, tie};\n                if (best == -1 || cur < bestPair) {\n                    best = v;\n                    bestPair = cur;\n                }\n            }\n            return best;\n        }\n    }\n\n    int choose_consensus_candidate(const array<PeelInfo, H>& infos, int m, int r, int smode) const {\n        const vector<int>& safe = infos[0].safe0;\n        if (safe.empty()) return -1;\n\n        vector<int> avgPos(V, 0), spread(V, 0);\n        for (int v : safe) {\n            int mn = (int)1e9, mx = -(int)1e9, sum = 0;\n            for (int h = 0; h < H; ++h) {\n                int p = infos[h].pos[v];\n                sum += p;\n                mn = min(mn, p);\n                mx = max(mx, p);\n            }\n            avgPos[v] = sum;\n            spread[v] = mx - mn;\n        }\n\n        if (smode == 0) {\n            vector<int> ord = safe;\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (avgPos[a] != avgPos[b]) return avgPos[a] > avgPos[b];\n                if (spread[a] != spread[b]) return spread[a] < spread[b];\n                return a < b;\n            });\n            int idx = (int)((long long)r * (int)ord.size() / m);\n            if (idx >= (int)ord.size()) idx = (int)ord.size() - 1;\n            return ord[idx];\n        } else {\n            int target = m - 1 - r;\n            int target3 = target * H;\n            int best = -1;\n            tuple<int, int, int, int> bestKey;\n            for (int v : safe) {\n                int d = abs(avgPos[v] - target3);\n                int tie = (target * 2 >= m - 1) ? -avgPos[v] : avgPos[v];\n                auto key = make_tuple(d, spread[v], tie, v);\n                if (best == -1 || key < bestKey) {\n                    best = v;\n                    bestKey = key;\n                }\n            }\n            return best;\n        }\n    }\n\n    int count_safe_after(const array<char, V>& occupied, int chosen) const {\n        array<char, V> occ2 = occupied;\n        occ2[chosen] = 1;\n        PeelInfo nxt = peel_info(occ2, 0);\n        return (int)nxt.safe0.size();\n    }\n\n    int choose_cell_online(const array<char, V>& occupied, const Fenwick& unseen, int t) const {\n        int m = unseen.total();\n        int r = unseen.sumPrefix(t);\n\n        int base = choose_cell_base(occupied, unseen, t, best_strategy);\n        if (m > LATE_REM) return base;\n\n        array<PeelInfo, H> infos;\n        for (int h = 0; h < H; ++h) infos[h] = peel_info(occupied, h);\n\n        const PeelInfo& baseInfo = infos[best_strategy.hmode];\n        const vector<int>& safe = baseInfo.safe0;\n        if (safe.empty() || (int)safe.size() == 1) return base;\n\n        int targetPos = m - 1 - r;\n\n        vector<int> byBase = safe;\n        sort(byBase.begin(), byBase.end(), [&](int a, int b) {\n            if (baseInfo.pos[a] != baseInfo.pos[b]) return baseInfo.pos[a] > baseInfo.pos[b];\n            return a < b;\n        });\n\n        vector<int> rankInBase(V, -1);\n        for (int i = 0; i < (int)byBase.size(); ++i) rankInBase[byBase[i]] = i;\n        int targetRank = (int)((long long)r * (int)byBase.size() / m);\n        if (targetRank >= (int)byBase.size()) targetRank = (int)byBase.size() - 1;\n\n        vector<int> avgPos(V, 0), spread(V, 0);\n        for (int v : safe) {\n            int mn = (int)1e9, mx = -(int)1e9, sum = 0;\n            for (int h = 0; h < H; ++h) {\n                int p = infos[h].pos[v];\n                sum += p;\n                mn = min(mn, p);\n                mx = max(mx, p);\n            }\n            avgPos[v] = sum;\n            spread[v] = mx - mn;\n        }\n\n        vector<int> cand;\n        array<char, V> used{};\n        used.fill(0);\n\n        auto add_cand = [&](int v) {\n            if (v < 0) return;\n            if (!used[v]) {\n                used[v] = 1;\n                cand.push_back(v);\n            }\n        };\n\n        add_cand(base);\n        for (int h = 0; h < H; ++h) {\n            add_cand(choose_cell_base(occupied, unseen, t, Strategy{h, best_strategy.smode}));\n        }\n        add_cand(choose_consensus_candidate(infos, m, r, best_strategy.smode));\n\n        int best = base;\n        bool first = true;\n        tuple<int, int, int, int, int, int> bestKey;\n\n        for (int v : cand) {\n            int rankDiff = abs(rankInBase[v] - targetRank);\n            int posDiff = abs(baseInfo.pos[v] - targetPos);\n            int avgDiff = abs(avgPos[v] - targetPos * H);\n            int flex = count_safe_after(occupied, v);\n            int tie = (targetPos * 2 >= m - 1) ? -baseInfo.pos[v] : baseInfo.pos[v];\n\n            tuple<int, int, int, int, int, int> key;\n            if (best_strategy.smode == 0) {\n                key = make_tuple(rankDiff, posDiff, avgDiff, spread[v], -flex, v);\n            } else {\n                key = make_tuple(posDiff, rankDiff, avgDiff, spread[v], -flex, v);\n            }\n\n            if (first || key < bestKey) {\n                first = false;\n                bestKey = key;\n                best = v;\n            }\n        }\n\n        return best;\n    }\n\n    vector<int> unload_sequence_labels(const array<char, V>& occ0, const array<int, V>& lbl) const {\n        array<char, V> occ = occ0;\n        array<char, V> vis{}, inFrontier{};\n        vis.fill(0);\n        inFrontier.fill(0);\n\n        queue<int> q;\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n        auto expand = [&](int s) {\n            if (vis[s]) return;\n            vis[s] = 1;\n            q.push(s);\n            while (!q.empty()) {\n                int u = q.front();\n                q.pop();\n                for (int v : adj[u]) {\n                    if (occ[v]) {\n                        if (!inFrontier[v]) {\n                            inFrontier[v] = 1;\n                            pq.push({lbl[v], v});\n                        }\n                    } else {\n                        if (!vis[v]) {\n                            vis[v] = 1;\n                            q.push(v);\n                        }\n                    }\n                }\n            }\n        };\n\n        expand(root);\n\n        vector<int> out;\n        out.reserve(M);\n        while ((int)out.size() < M) {\n            while (!pq.empty() && !occ[pq.top().second]) pq.pop();\n            if (pq.empty()) break;\n            int v = pq.top().second;\n            pq.pop();\n            out.push_back(lbl[v]);\n            occ[v] = 0;\n            expand(v);\n        }\n        return out;\n    }\n\n    vector<int> unload_sequence_vertices(const array<char, V>& occ0, const array<int, V>& lbl) const {\n        array<char, V> occ = occ0;\n        array<char, V> vis{}, inFrontier{};\n        vis.fill(0);\n        inFrontier.fill(0);\n\n        queue<int> q;\n        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n        auto expand = [&](int s) {\n            if (vis[s]) return;\n            vis[s] = 1;\n            q.push(s);\n            while (!q.empty()) {\n                int u = q.front();\n                q.pop();\n                for (int v : adj[u]) {\n                    if (occ[v]) {\n                        if (!inFrontier[v]) {\n                            inFrontier[v] = 1;\n                            pq.push({lbl[v], v});\n                        }\n                    } else {\n                        if (!vis[v]) {\n                            vis[v] = 1;\n                            q.push(v);\n                        }\n                    }\n                }\n            }\n        };\n\n        expand(root);\n\n        vector<int> out;\n        out.reserve(M);\n        while ((int)out.size() < M) {\n            while (!pq.empty() && !occ[pq.top().second]) pq.pop();\n            if (pq.empty()) break;\n            int v = pq.top().second;\n            pq.pop();\n            out.push_back(v);\n            occ[v] = 0;\n            expand(v);\n        }\n        return out;\n    }\n\n    long long count_inversions(const vector<int>& a) const {\n        Fenwick fw(M);\n        long long inv = 0;\n        for (int i = 0; i < (int)a.size(); ++i) {\n            int x = a[i];\n            inv += i - fw.sumPrefix(x + 1);\n            fw.add(x, 1);\n        }\n        return inv;\n    }\n\n    long long simulate(const Strategy& st, const vector<int>& perm) const {\n        array<char, V> occ{};\n        occ.fill(0);\n        array<int, V> lbl;\n        lbl.fill(-1);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int x : perm) {\n            int c = choose_cell_base(occ, unseen, x, st);\n            occ[c] = 1;\n            lbl[c] = x;\n            unseen.add(x, -1);\n        }\n\n        vector<int> out = unload_sequence_labels(occ, lbl);\n        return count_inversions(out);\n    }\n\n    void train_best_strategy() {\n        vector<Strategy> cand = {\n            {0, 0}, {0, 1},\n            {1, 0}, {1, 1},\n            {2, 0}, {2, 1}\n        };\n\n        uint64_t seed = 1469598103934665603ULL;\n        seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL;\n        for (int v = 0; v < V; ++v) {\n            if (obstacle[v]) {\n                seed ^= (uint64_t)(v + 1);\n                seed *= 1099511628211ULL;\n            }\n        }\n        mt19937_64 rng(seed);\n\n        const int TRAIN_ITERS = 6;\n        vector<vector<int>> perms(TRAIN_ITERS, vector<int>(M));\n        for (int it = 0; it < TRAIN_ITERS; ++it) {\n            iota(perms[it].begin(), perms[it].end(), 0);\n            shuffle(perms[it].begin(), perms[it].end(), rng);\n        }\n\n        long long bestSum = (1LL << 62);\n        long long bestWorst = (1LL << 62);\n\n        for (const auto& st : cand) {\n            long long sumInv = 0;\n            long long worstInv = 0;\n            for (int it = 0; it < TRAIN_ITERS; ++it) {\n                long long inv = simulate(st, perms[it]);\n                sumInv += inv;\n                worstInv = max(worstInv, inv);\n            }\n            if (sumInv < bestSum || (sumInv == bestSum && worstInv < bestWorst)) {\n                bestSum = sumInv;\n                bestWorst = worstInv;\n                best_strategy = st;\n            }\n        }\n    }\n\npublic:\n    void solve() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> D >> N;\n        root = id(0, (D - 1) / 2);\n\n        obstacle.fill(0);\n        label.fill(-1);\n\n        for (int k = 0; k < N; ++k) {\n            int i, j;\n            cin >> i >> j;\n            obstacle[id(i, j)] = 1;\n        }\n\n        build_adj();\n\n        cells.clear();\n        for (int v = 0; v < V; ++v) {\n            if (!obstacle[v] && v != root) cells.push_back(v);\n        }\n        M = (int)cells.size();\n\n        array<char, V> active{};\n        active.fill(0);\n        for (int v = 0; v < V; ++v) if (!obstacle[v]) active[v] = 1;\n        bfs_dist(active, dist0);\n\n        train_best_strategy();\n\n        array<char, V> occupied{};\n        occupied.fill(0);\n\n        Fenwick unseen(M);\n        for (int x = 0; x < M; ++x) unseen.add(x, 1);\n\n        for (int d = 0; d < M; ++d) {\n            int t;\n            cin >> t;\n\n            int c = choose_cell_online(occupied, unseen, t);\n            occupied[c] = 1;\n            label[c] = t;\n            unseen.add(t, -1);\n\n            cout << (c / D) << ' ' << (c % D) << '\\n';\n            cout.flush();\n        }\n\n        vector<int> unload = unload_sequence_vertices(occupied, label);\n        for (int v : unload) {\n            cout << (v / D) << ' ' << (v % D) << '\\n';\n        }\n        cout.flush();\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing Clock = chrono::steady_clock;\n\nstatic constexpr int MAXN = 50;\nstatic constexpr int MAXV = 2500;\nstatic constexpr int MAXC = 101;\nstatic constexpr int INF_INT = 1e9;\n\nint n, m;\nbool origAdj[MAXC][MAXC];\nint distColor[MAXC];\nint degColor[MAXC];\nvector<vector<int>> depthGroups;\n\nstruct Board {\n    int h = 0, w = 0;\n    array<unsigned char, MAXV> a{};\n    int nonzero = 0;\n    long long distsum = 0;\n};\n\ninline bool better_board(const Board& x, const Board& y) {\n    if (x.nonzero != y.nonzero) return x.nonzero < y.nonzero;\n    if (x.distsum != y.distsum) return x.distsum < y.distsum;\n    return x.h * x.w < y.h * y.w;\n}\n\ninline bool not_worse_board(const Board& x, const Board& y) {\n    return !better_board(y, x);\n}\n\nuint64_t hash_board(const Board& b) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)b.h + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    h ^= (uint64_t)b.w + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    int V = b.h * b.w;\n    for (int i = 0; i < V; ++i) {\n        h ^= (uint64_t)(b.a[i] + 1) + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n    }\n    return h;\n}\n\nvoid compute_stats(Board& b) {\n    b.nonzero = 0;\n    b.distsum = 0;\n    int V = b.h * b.w;\n    for (int i = 0; i < V; ++i) {\n        int c = b.a[i];\n        if (c != 0) ++b.nonzero;\n        b.distsum += distColor[c];\n    }\n}\n\ninline bool row_all_zero(const Board& b, int r) {\n    int base = r * b.w;\n    for (int j = 0; j < b.w; ++j) {\n        if (b.a[base + j] != 0) return false;\n    }\n    return true;\n}\n\ninline bool col_all_zero(const Board& b, int c) {\n    for (int i = 0; i < b.h; ++i) {\n        if (b.a[i * b.w + c] != 0) return false;\n    }\n    return true;\n}\n\nBoard delete_row_board(const Board& b, int r, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h - 1;\n    nb.w = b.w;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r) continue;\n        memcpy(&nb.a[p], &b.a[i * b.w], b.w * sizeof(unsigned char));\n        p += b.w;\n    }\n    return nb;\n}\n\nBoard delete_col_board(const Board& b, int c, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h;\n    nb.w = b.w - 1;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nBoard delete_rows2_board(const Board& b, int r1, int r2, int gainNz, long long gainDist) {\n    if (r1 > r2) swap(r1, r2);\n    Board nb;\n    nb.h = b.h - 2;\n    nb.w = b.w;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r1 || i == r2) continue;\n        memcpy(&nb.a[p], &b.a[i * b.w], b.w * sizeof(unsigned char));\n        p += b.w;\n    }\n    return nb;\n}\n\nBoard delete_cols2_board(const Board& b, int c1, int c2, int gainNz, long long gainDist) {\n    if (c1 > c2) swap(c1, c2);\n    Board nb;\n    nb.h = b.h;\n    nb.w = b.w - 2;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c1 || j == c2) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nBoard delete_rowcol_board(const Board& b, int r, int c, int gainNz, long long gainDist) {\n    Board nb;\n    nb.h = b.h - 1;\n    nb.w = b.w - 1;\n    nb.nonzero = b.nonzero - gainNz;\n    nb.distsum = b.distsum - gainDist;\n    int p = 0;\n    for (int i = 0; i < b.h; ++i) {\n        if (i == r) continue;\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) {\n            if (j == c) continue;\n            nb.a[p++] = b.a[base + j];\n        }\n    }\n    return nb;\n}\n\nvoid crop_zero_border(Board& b) {\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        while (b.h > 1 && row_all_zero(b, 0)) {\n            b = delete_row_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.h > 1 && row_all_zero(b, b.h - 1)) {\n            b = delete_row_board(b, b.h - 1, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, 0)) {\n            b = delete_col_board(b, 0, 0, 0);\n            changed = true;\n        }\n        while (b.w > 1 && col_all_zero(b, b.w - 1)) {\n            b = delete_col_board(b, b.w - 1, 0, 0);\n            changed = true;\n        }\n    }\n}\n\nint sparse_score(const Board& b) {\n    int r1 = INF_INT, r2 = INF_INT;\n    for (int i = 0; i < b.h; ++i) {\n        int cnt = 0;\n        int base = i * b.w;\n        for (int j = 0; j < b.w; ++j) cnt += (b.a[base + j] != 0);\n        if (cnt < r1) { r2 = r1; r1 = cnt; }\n        else if (cnt < r2) r2 = cnt;\n    }\n\n    int c1 = INF_INT, c2 = INF_INT;\n    for (int j = 0; j < b.w; ++j) {\n        int cnt = 0;\n        for (int i = 0; i < b.h; ++i) cnt += (b.a[i * b.w + j] != 0);\n        if (cnt < c1) { c2 = c1; c1 = cnt; }\n        else if (cnt < c2) c2 = cnt;\n    }\n\n    if (r1 == INF_INT) r1 = 0;\n    if (r2 == INF_INT) r2 = r1;\n    if (c1 == INF_INT) c1 = 0;\n    if (c2 == INF_INT) c2 = c1;\n    return r1 + r2 + c1 + c2;\n}\n\nbool is_legal(const Board& b) {\n    static int cnt[MAXC], firstPos[MAXC];\n    static bool adj[MAXC][MAXC];\n    static int vis[MAXV];\n    static int q[MAXV];\n    static int vis0[(MAXN + 2) * (MAXN + 2)];\n    static int q0[(MAXN + 2) * (MAXN + 2)];\n\n    memset(cnt, 0, sizeof(cnt));\n    memset(firstPos, -1, sizeof(firstPos));\n    memset(adj, 0, sizeof(adj));\n\n    int h = b.h, w = b.w;\n    int zeroCnt = 0;\n\n    for (int i = 0; i < h; ++i) {\n        int base = i * w;\n        for (int j = 0; j < w; ++j) {\n            int idx = base + j;\n            int c = b.a[idx];\n            if (c == 0) {\n                ++zeroCnt;\n            } else {\n                ++cnt[c];\n                if (firstPos[c] == -1) firstPos[c] = idx;\n            }\n\n            if ((i == 0 || i == h - 1 || j == 0 || j == w - 1) && c != 0) {\n                adj[c][0] = adj[0][c] = true;\n            }\n            if (i + 1 < h) {\n                int d = b.a[idx + w];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n            if (j + 1 < w) {\n                int d = b.a[idx + 1];\n                if (c != d) adj[c][d] = adj[d][c] = true;\n            }\n        }\n    }\n\n    for (int c = 1; c <= m; ++c) {\n        if (cnt[c] == 0) return false;\n    }\n\n    for (int c = 0; c <= m; ++c) {\n        for (int d = 0; d <= m; ++d) {\n            if (adj[c][d] != origAdj[c][d]) return false;\n        }\n    }\n\n    memset(vis, 0, sizeof(vis));\n    int stamp = 1;\n\n    for (int color = 1; color <= m; ++color) {\n        if (cnt[color] <= 1) {\n            ++stamp;\n            continue;\n        }\n\n        int start = firstPos[color];\n        int ql = 0, qr = 0;\n        q[qr++] = start;\n        vis[start] = stamp;\n        int seen = 1;\n\n        while (ql < qr) {\n            int v = q[ql++];\n            int x = v / w, y = v % w;\n\n            if (x > 0) {\n                int to = v - w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (x + 1 < h && seen < cnt[color]) {\n                int to = v + w;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (y > 0 && seen < cnt[color]) {\n                int to = v - 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n            if (y + 1 < w && seen < cnt[color]) {\n                int to = v + 1;\n                if (b.a[to] == color && vis[to] != stamp) {\n                    vis[to] = stamp;\n                    q[qr++] = to;\n                    if (++seen == cnt[color]) break;\n                }\n            }\n        }\n\n        if (seen != cnt[color]) return false;\n        ++stamp;\n    }\n\n    if (zeroCnt > 0) {\n        int H = h + 2, W = w + 2;\n        memset(vis0, 0, sizeof(vis0));\n        int ql = 0, qr = 0;\n        q0[qr++] = 0;\n        vis0[0] = 1;\n        int reachedZero = 0;\n\n        auto can_pass = [&](int r, int c) -> bool {\n            if (r < 0 || r >= H || c < 0 || c >= W) return false;\n            int id = r * W + c;\n            if (vis0[id]) return false;\n            if (r == 0 || r == H - 1 || c == 0 || c == W - 1) return true;\n            return b.a[(r - 1) * w + (c - 1)] == 0;\n        };\n\n        while (ql < qr) {\n            int v = q0[ql++];\n            int r = v / W, c = v % W;\n            static const int dr[4] = {-1, 1, 0, 0};\n            static const int dc[4] = {0, 0, -1, 1};\n            for (int k = 0; k < 4; ++k) {\n                int nr = r + dr[k], nc = c + dc[k];\n                if (!can_pass(nr, nc)) continue;\n                int nid = nr * W + nc;\n                vis0[nid] = 1;\n                q0[qr++] = nid;\n                if (1 <= nr && nr <= h && 1 <= nc && nc <= w) ++reachedZero;\n            }\n        }\n\n        if (reachedZero != zeroCnt) return false;\n    }\n\n    return true;\n}\n\nstruct ShrinkCand {\n    Board nb;\n    int sparse = 0;\n};\n\nstruct LineInfo {\n    int nz;\n    long long dist;\n    int idx;\n};\n\nBoard shrink_pass(Board b, mt19937& rng, Clock::time_point deadline, int randomTopK) {\n    crop_zero_border(b);\n    compute_stats(b);\n\n    static constexpr int PAIR_TOP = 5;\n    static constexpr int CROSS_TOP = 4;\n\n    auto add_candidate = [&](vector<ShrinkCand>& cands, Board&& nb) {\n        crop_zero_border(nb);\n        if (!is_legal(nb)) return;\n        ShrinkCand sc;\n        sc.nb = nb;\n        sc.sparse = sparse_score(nb);\n        cands.push_back(std::move(sc));\n    };\n\n    while (Clock::now() < deadline) {\n        vector<int> rowNz(b.h, 0), colNz(b.w, 0);\n        vector<long long> rowDist(b.h, 0), colDist(b.w, 0);\n\n        for (int i = 0; i < b.h; ++i) {\n            int base = i * b.w;\n            for (int j = 0; j < b.w; ++j) {\n                int c = b.a[base + j];\n                rowNz[i] += (c != 0);\n                colNz[j] += (c != 0);\n                rowDist[i] += distColor[c];\n                colDist[j] += distColor[c];\n            }\n        }\n\n        vector<ShrinkCand> cands;\n        cands.reserve(b.h + b.w + 48);\n        int bestSingleNZ = b.nonzero;\n\n        if (b.h > 1) {\n            for (int r = 0; r < b.h; ++r) {\n                if ((r & 7) == 0 && Clock::now() >= deadline) return b;\n                Board nb = delete_row_board(b, r, rowNz[r], rowDist[r]);\n                crop_zero_border(nb);\n                if (!is_legal(nb)) continue;\n                ShrinkCand sc;\n                sc.nb = nb;\n                sc.sparse = sparse_score(nb);\n                bestSingleNZ = min(bestSingleNZ, nb.nonzero);\n                cands.push_back(std::move(sc));\n            }\n        }\n        if (b.w > 1) {\n            for (int c = 0; c < b.w; ++c) {\n                if ((c & 7) == 0 && Clock::now() >= deadline) return b;\n                Board nb = delete_col_board(b, c, colNz[c], colDist[c]);\n                crop_zero_border(nb);\n                if (!is_legal(nb)) continue;\n                ShrinkCand sc;\n                sc.nb = nb;\n                sc.sparse = sparse_score(nb);\n                bestSingleNZ = min(bestSingleNZ, nb.nonzero);\n                cands.push_back(std::move(sc));\n            }\n        }\n\n        // Macro escape only if singles don't directly improve score.\n        if (cands.empty() || bestSingleNZ >= b.nonzero) {\n            vector<LineInfo> rows, cols;\n            rows.reserve(b.h);\n            cols.reserve(b.w);\n            for (int i = 0; i < b.h; ++i) rows.push_back({rowNz[i], rowDist[i], i});\n            for (int j = 0; j < b.w; ++j) cols.push_back({colNz[j], colDist[j], j});\n\n            shuffle(rows.begin(), rows.end(), rng);\n            shuffle(cols.begin(), cols.end(), rng);\n\n            stable_sort(rows.begin(), rows.end(), [](const LineInfo& a, const LineInfo& b) {\n                if (a.nz != b.nz) return a.nz < b.nz;\n                if (a.dist != b.dist) return a.dist < b.dist;\n                return a.idx < b.idx;\n            });\n            stable_sort(cols.begin(), cols.end(), [](const LineInfo& a, const LineInfo& b) {\n                if (a.nz != b.nz) return a.nz < b.nz;\n                if (a.dist != b.dist) return a.dist < b.dist;\n                return a.idx < b.idx;\n            });\n\n            int rt = min<int>(PAIR_TOP, (int)rows.size());\n            int ct = min<int>(PAIR_TOP, (int)cols.size());\n\n            if (b.h > 2) {\n                for (int i = 0; i < rt; ++i) {\n                    for (int j = i + 1; j < rt; ++j) {\n                        if (((i * rt + j) & 15) == 0 && Clock::now() >= deadline) return b;\n                        int r1 = rows[i].idx, r2 = rows[j].idx;\n                        Board nb = delete_rows2_board(\n                            b, r1, r2,\n                            rowNz[r1] + rowNz[r2],\n                            rowDist[r1] + rowDist[r2]\n                        );\n                        add_candidate(cands, std::move(nb));\n                    }\n                }\n            }\n\n            if (b.w > 2) {\n                for (int i = 0; i < ct; ++i) {\n                    for (int j = i + 1; j < ct; ++j) {\n                        if (((i * ct + j) & 15) == 0 && Clock::now() >= deadline) return b;\n                        int c1 = cols[i].idx, c2 = cols[j].idx;\n                        Board nb = delete_cols2_board(\n                            b, c1, c2,\n                            colNz[c1] + colNz[c2],\n                            colDist[c1] + colDist[c2]\n                        );\n                        add_candidate(cands, std::move(nb));\n                    }\n                }\n            }\n\n            if (b.h > 1 && b.w > 1) {\n                rt = min<int>(CROSS_TOP, (int)rows.size());\n                ct = min<int>(CROSS_TOP, (int)cols.size());\n                for (int i = 0; i < rt; ++i) {\n                    for (int j = 0; j < ct; ++j) {\n                        if (((i * ct + j) & 15) == 0 && Clock::now() >= deadline) return b;\n                        int r = rows[i].idx, c = cols[j].idx;\n                        int cell = b.a[r * b.w + c];\n                        int gainNz = rowNz[r] + colNz[c] - (cell != 0);\n                        long long gainDist = rowDist[r] + colDist[c] - distColor[cell];\n                        Board nb = delete_rowcol_board(b, r, c, gainNz, gainDist);\n                        add_candidate(cands, std::move(nb));\n                    }\n                }\n            }\n        }\n\n        if (cands.empty()) break;\n\n        sort(cands.begin(), cands.end(), [](const ShrinkCand& x, const ShrinkCand& y) {\n            if (x.nb.nonzero != y.nb.nonzero) return x.nb.nonzero < y.nb.nonzero;\n            if (x.sparse != y.sparse) return x.sparse < y.sparse;\n            int ax = x.nb.h * x.nb.w, ay = y.nb.h * y.nb.w;\n            if (ax != ay) return ax < ay;\n            if (x.nb.distsum != y.nb.distsum) return x.nb.distsum < y.nb.distsum;\n            return false;\n        });\n\n        // Cheap improvement: if score is directly improved, randomize only among equally best-improving candidates.\n        int lim = 1;\n        if (cands[0].nb.nonzero < b.nonzero) {\n            int bestNZ = cands[0].nb.nonzero;\n            while (lim < (int)cands.size() && lim < max(2, randomTopK) && cands[lim].nb.nonzero == bestNZ) {\n                ++lim;\n            }\n        } else {\n            lim = min<int>((int)cands.size(), max(1, randomTopK));\n        }\n\n        int pick = 0;\n        if (lim > 1) {\n            int a = uniform_int_distribution<int>(0, lim - 1)(rng);\n            int bb = uniform_int_distribution<int>(0, lim - 1)(rng);\n            pick = min(a, bb);\n        }\n\n        b = cands[pick].nb;\n        crop_zero_border(b);\n    }\n\n    return b;\n}\n\nstruct LSState {\n    int h = 0, w = 0, V = 0;\n    array<unsigned char, MAXV> g{};\n    array<int, MAXC> cnt{};\n    int edge[MAXC][MAXC];\n    long long distSum = 0;\n    int nonzero = 0;\n\n    array<array<short, 4>, MAXV> nbr{};\n    array<unsigned char, MAXV> nbrCnt{};\n    array<unsigned char, MAXV> bside{};\n\n    int rowNZ[MAXN]{};\n    int colNZ[MAXN]{};\n};\n\nLSState build_state(const Board& b) {\n    LSState st;\n    st.h = b.h;\n    st.w = b.w;\n    st.V = b.h * b.w;\n    st.cnt.fill(0);\n    memset(st.edge, 0, sizeof(st.edge));\n    memset(st.rowNZ, 0, sizeof(st.rowNZ));\n    memset(st.colNZ, 0, sizeof(st.colNZ));\n    st.distSum = 0;\n    st.nonzero = 0;\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = b.a[idx];\n        st.g[idx] = b.a[idx];\n        ++st.cnt[c];\n        st.distSum += distColor[c];\n        if (c != 0) {\n            ++st.nonzero;\n            ++st.rowNZ[idx / st.w];\n            ++st.colNZ[idx % st.w];\n        }\n    }\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int i = idx / st.w, j = idx % st.w;\n        int k = 0;\n        if (i > 0) st.nbr[idx][k++] = idx - st.w;\n        if (i + 1 < st.h) st.nbr[idx][k++] = idx + st.w;\n        if (j > 0) st.nbr[idx][k++] = idx - 1;\n        if (j + 1 < st.w) st.nbr[idx][k++] = idx + 1;\n        st.nbrCnt[idx] = (unsigned char)k;\n        st.bside[idx] = (unsigned char)((i == 0) + (i == st.h - 1) + (j == 0) + (j == st.w - 1));\n    }\n\n    auto add_edge = [&](int a, int b, int delta) {\n        if (a == b) return;\n        st.edge[a][b] += delta;\n        st.edge[b][a] += delta;\n    };\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        int c = st.g[idx];\n        int i = idx / st.w, j = idx % st.w;\n        if (i == 0) add_edge(c, 0, 1);\n        if (i == st.h - 1) add_edge(c, 0, 1);\n        if (j == 0) add_edge(c, 0, 1);\n        if (j == st.w - 1) add_edge(c, 0, 1);\n        if (i + 1 < st.h) add_edge(c, st.g[idx + st.w], 1);\n        if (j + 1 < st.w) add_edge(c, st.g[idx + 1], 1);\n    }\n\n    return st;\n}\n\nstatic int conn_vis[MAXV];\nstatic int conn_stamp = 1;\n\nbool connected_after_remove(const LSState& st, int color, int remIdx, int need, int startIdx) {\n    ++conn_stamp;\n    if (conn_stamp == INT_MAX) {\n        memset(conn_vis, 0, sizeof(conn_vis));\n        conn_stamp = 1;\n    }\n\n    static int q[MAXV];\n    int ql = 0, qr = 0;\n    q[qr++] = startIdx;\n    conn_vis[startIdx] = conn_stamp;\n    int seen = 1;\n\n    while (ql < qr) {\n        int v = q[ql++];\n        int deg = st.nbrCnt[v];\n        for (int k = 0; k < deg; ++k) {\n            int to = st.nbr[v][k];\n            if (to == remIdx) continue;\n            if (st.g[to] != color) continue;\n            if (conn_vis[to] == conn_stamp) continue;\n            conn_vis[to] = conn_stamp;\n            q[qr++] = to;\n            if (++seen == need) return true;\n        }\n    }\n    return seen == need;\n}\n\ninline bool can_to_zero(const LSState& st, int idx) {\n    if (st.bside[idx] > 0) return true;\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        if (st.g[st.nbr[idx][k]] == 0) return true;\n    }\n    return false;\n}\n\nvoid compute_zero_dist(const LSState& st, vector<int>& zd) {\n    zd.assign(st.V, INF_INT);\n    static int q[MAXV];\n    int ql = 0, qr = 0;\n\n    for (int idx = 0; idx < st.V; ++idx) {\n        if (st.g[idx] == 0 || can_to_zero(st, idx)) {\n            zd[idx] = 0;\n            q[qr++] = idx;\n        }\n    }\n\n    while (ql < qr) {\n        int v = q[ql++];\n        int nd = zd[v] + 1;\n        int deg = st.nbrCnt[v];\n        for (int k = 0; k < deg; ++k) {\n            int to = st.nbr[v][k];\n            if (zd[to] > nd) {\n                zd[to] = nd;\n                q[qr++] = to;\n            }\n        }\n    }\n}\n\nbool try_move(LSState& st, int idx, int t) {\n    int c = st.g[idx];\n    if (c == 0 || c == t) return false;\n    if (st.cnt[c] <= 1) return false;\n\n    int sameNbr = 0;\n    int startIdx = -1;\n    bool targetConnected = false;\n\n    if (t == 0 && st.bside[idx] > 0) targetConnected = true;\n\n    int pa[12], pb[12], pd[12];\n    int pnum = 0;\n\n    auto add_change = [&](int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        for (int i = 0; i < pnum; ++i) {\n            if (pa[i] == a && pb[i] == b) {\n                pd[i] += d;\n                return;\n            }\n        }\n        pa[pnum] = a;\n        pb[pnum] = b;\n        pd[pnum] = d;\n        ++pnum;\n    };\n\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) {\n        int to = st.nbr[idx][k];\n        int d = st.g[to];\n\n        if (d == c) {\n            ++sameNbr;\n            startIdx = to;\n        }\n        if (d == t) targetConnected = true;\n        if (t == 0 && d == 0) targetConnected = true;\n\n        if (c != d) add_change(c, d, -1);\n        if (t != d) add_change(t, d, +1);\n    }\n\n    if (st.bside[idx] > 0) {\n        add_change(c, 0, -st.bside[idx]);\n        add_change(t, 0, +st.bside[idx]);\n    }\n\n    if (!targetConnected) return false;\n    if (sameNbr == 0) return false;\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        int nc = st.edge[a][b] + pd[i];\n        if (nc < 0) return false;\n        bool nadj = (nc > 0);\n        if (nadj != origAdj[a][b]) return false;\n    }\n\n    if (sameNbr >= 2) {\n        if (!connected_after_remove(st, c, idx, st.cnt[c] - 1, startIdx)) return false;\n    }\n\n    st.g[idx] = (unsigned char)t;\n    --st.cnt[c];\n    ++st.cnt[t];\n    st.distSum += (long long)distColor[t] - distColor[c];\n\n    if (t == 0) {\n        --st.nonzero;\n        --st.rowNZ[idx / st.w];\n        --st.colNZ[idx % st.w];\n    }\n\n    for (int i = 0; i < pnum; ++i) {\n        int a = pa[i], b = pb[i];\n        st.edge[a][b] += pd[i];\n        st.edge[b][a] += pd[i];\n    }\n\n    return true;\n}\n\narray<int, MAXC> make_key(const LSState& st, mt19937& rng) {\n    array<int, MAXC> key{};\n    key.fill(0);\n    key[0] = 0;\n\n    for (int d = 1; d < (int)depthGroups.size(); ++d) {\n        vector<int> v = depthGroups[d];\n        shuffle(v.begin(), v.end(), rng);\n        stable_sort(v.begin(), v.end(), [&](int a, int b) {\n            if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n            if (degColor[a] != degColor[b]) return degColor[a] > degColor[b];\n            return a < b;\n        });\n        for (int i = 0; i < (int)v.size(); ++i) {\n            key[v[i]] = d * 1000 + (i + 1);\n        }\n    }\n    return key;\n}\n\nbool attempt_best_move(LSState& st, int idx, const array<int, MAXC>& key, bool permissive_same_depth) {\n    int c = st.g[idx];\n    if (c == 0) return false;\n\n    int cand[5];\n    int ccnt = 0;\n\n    auto add_cand = [&](int x) {\n        if (x == c) return;\n\n        if (x != 0) {\n            if (distColor[x] > distColor[c]) return;\n\n            if (distColor[x] == distColor[c]) {\n                if (!permissive_same_depth) {\n                    if (key[x] >= key[c]) return;\n                } else {\n                    if (st.cnt[x] < st.cnt[c]) return;\n                    if (st.cnt[x] == st.cnt[c] && key[x] >= key[c]) return;\n                }\n            }\n        }\n\n        for (int i = 0; i < ccnt; ++i) {\n            if (cand[i] == x) return;\n        }\n        cand[ccnt++] = x;\n    };\n\n    if (can_to_zero(st, idx)) add_cand(0);\n    int deg = st.nbrCnt[idx];\n    for (int k = 0; k < deg; ++k) add_cand(st.g[st.nbr[idx][k]]);\n\n    sort(cand, cand + ccnt, [&](int a, int b) {\n        if (a == 0 || b == 0) return a == 0;\n        if (distColor[a] != distColor[b]) return distColor[a] < distColor[b];\n        if (st.cnt[a] != st.cnt[b]) return st.cnt[a] > st.cnt[b];\n        if (key[a] != key[b]) return key[a] < key[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < ccnt; ++i) {\n        if (try_move(st, idx, cand[i])) return true;\n    }\n    return false;\n}\n\nbool global_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n    vector<int> zeroDist;\n    compute_zero_dist(st, zeroDist);\n\n    vector<int> ord(st.V);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng);\n\n    stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int ca = st.g[a], cb = st.g[b];\n        if (ca == 0 || cb == 0) return ca != 0;\n\n        if (zeroDist[a] != zeroDist[b]) return zeroDist[a] < zeroDist[b];\n\n        int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n        int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n        if (ma != mb) return ma < mb;\n\n        if (distColor[ca] != distColor[cb]) return distColor[ca] > distColor[cb];\n        if (key[ca] != key[cb]) return key[ca] > key[cb];\n\n        int sa = st.rowNZ[a / st.w] + st.colNZ[a % st.w];\n        int sb = st.rowNZ[b / st.w] + st.colNZ[b % st.w];\n        return sa < sb;\n    });\n\n    bool moved = false;\n    for (int it = 0; it < st.V; ++it) {\n        if ((it & 255) == 0 && Clock::now() >= deadline) break;\n        int idx = ord[it];\n        if (attempt_best_move(st, idx, key, false)) moved = true;\n    }\n    return moved;\n}\n\nbool line_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n    vector<int> zeroDist;\n    compute_zero_dist(st, zeroDist);\n\n    vector<pair<int, int>> lines;\n    lines.reserve(st.h + st.w);\n    for (int i = 0; i < st.h; ++i) if (st.rowNZ[i] > 0) lines.push_back({st.rowNZ[i], i});\n    for (int j = 0; j < st.w; ++j) if (st.colNZ[j] > 0) lines.push_back({st.colNZ[j], st.h + j});\n\n    if (lines.empty()) return false;\n\n    shuffle(lines.begin(), lines.end(), rng);\n    stable_sort(lines.begin(), lines.end(), [](const auto& a, const auto& b) {\n        return a.first < b.first;\n    });\n\n    int L = min<int>((int)lines.size(), 8);\n    bool moved = false;\n\n    for (int li = 0; li < L; ++li) {\n        if ((li & 3) == 0 && Clock::now() >= deadline) break;\n\n        int code = lines[li].second;\n        vector<int> cells;\n\n        if (code < st.h) {\n            int r = code;\n            cells.reserve(st.rowNZ[r]);\n            for (int j = 0; j < st.w; ++j) {\n                int idx = r * st.w + j;\n                if (st.g[idx] != 0) cells.push_back(idx);\n            }\n        } else {\n            int c = code - st.h;\n            cells.reserve(st.colNZ[c]);\n            for (int i = 0; i < st.h; ++i) {\n                int idx = i * st.w + c;\n                if (st.g[idx] != 0) cells.push_back(idx);\n            }\n        }\n\n        shuffle(cells.begin(), cells.end(), rng);\n        stable_sort(cells.begin(), cells.end(), [&](int a, int b) {\n            if (zeroDist[a] != zeroDist[b]) return zeroDist[a] < zeroDist[b];\n\n            int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n            int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n            if (ma != mb) return ma < mb;\n\n            int da = distColor[st.g[a]], db = distColor[st.g[b]];\n            if (da != db) return da > db;\n\n            if (st.cnt[st.g[a]] != st.cnt[st.g[b]]) return st.cnt[st.g[a]] < st.cnt[st.g[b]];\n            int ka = key[st.g[a]], kb = key[st.g[b]];\n            if (ka != kb) return ka > kb;\n\n            return false;\n        });\n\n        for (int idx : cells) {\n            if (Clock::now() >= deadline) break;\n            if (attempt_best_move(st, idx, key, true)) moved = true;\n        }\n    }\n\n    return moved;\n}\n\nbool frontier_round(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    auto key = make_key(st, rng);\n    vector<int> zeroDist;\n    compute_zero_dist(st, zeroDist);\n\n    vector<int> ord;\n    ord.reserve(st.V);\n    for (int idx = 0; idx < st.V; ++idx) {\n        if (st.g[idx] == 0) continue;\n        if (zeroDist[idx] <= 2) ord.push_back(idx);\n    }\n    if (ord.empty()) return false;\n\n    shuffle(ord.begin(), ord.end(), rng);\n    stable_sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (zeroDist[a] != zeroDist[b]) return zeroDist[a] < zeroDist[b];\n\n        int ma = min(st.rowNZ[a / st.w], st.colNZ[a % st.w]);\n        int mb = min(st.rowNZ[b / st.w], st.colNZ[b % st.w]);\n        if (ma != mb) return ma < mb;\n\n        int ca = st.g[a], cb = st.g[b];\n        if (distColor[ca] != distColor[cb]) return distColor[ca] > distColor[cb];\n        if (st.cnt[ca] != st.cnt[cb]) return st.cnt[ca] < st.cnt[cb];\n        if (key[ca] != key[cb]) return key[ca] > key[cb];\n\n        return false;\n    });\n\n    bool moved = false;\n    int lim = min<int>((int)ord.size(), 500);\n    for (int it = 0; it < lim; ++it) {\n        if ((it & 255) == 0 && Clock::now() >= deadline) break;\n        int idx = ord[it];\n        if (attempt_best_move(st, idx, key, false)) moved = true;\n    }\n    return moved;\n}\n\nvoid optimize(LSState& st, mt19937& rng, Clock::time_point deadline) {\n    int stagnation = 0;\n    int phase = 0;\n\n    while (Clock::now() < deadline && stagnation < 6) {\n        bool moved = false;\n\n        int mode = phase & 3;\n        if (mode == 0 || mode == 3) moved = global_round(st, rng, deadline);\n        else if (mode == 1) moved = line_round(st, rng, deadline);\n        else moved = frontier_round(st, rng, deadline);\n\n        if (!moved && Clock::now() < deadline) moved = frontier_round(st, rng, deadline);\n        if (!moved && Clock::now() < deadline) moved = line_round(st, rng, deadline);\n\n        if (moved) stagnation = 0;\n        else ++stagnation;\n        ++phase;\n    }\n}\n\nBoard state_to_board(const LSState& st) {\n    Board b;\n    b.h = st.h;\n    b.w = st.w;\n    b.nonzero = st.nonzero;\n    b.distsum = st.distSum;\n    for (int i = 0; i < st.V; ++i) b.a[i] = st.g[i];\n    return b;\n}\n\nBoard shave_pass(Board b, mt19937& rng, Clock::time_point deadline) {\n    crop_zero_border(b);\n    compute_stats(b);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(16);\n    seen.insert(hash_board(b));\n\n    int stagnation = 0;\n\n    while (Clock::now() < deadline && stagnation < 3) {\n        auto now = Clock::now();\n        auto rem_ms = chrono::duration_cast<chrono::milliseconds>(deadline - now).count();\n        int slice = (int)max<long long>(20, rem_ms / 2);\n        auto inner_deadline = min(deadline, now + chrono::milliseconds(slice));\n\n        LSState st = build_state(b);\n        optimize(st, rng, inner_deadline);\n        Board nb = state_to_board(st);\n        crop_zero_border(nb);\n        compute_stats(nb);\n\n        uint64_t h = hash_board(nb);\n        if (better_board(nb, b) || (not_worse_board(nb, b) && !seen.count(h))) {\n            b = nb;\n            seen.insert(h);\n            stagnation = 0;\n        } else {\n            ++stagnation;\n        }\n    }\n\n    return b;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> n >> m;\n\n    Board original;\n    original.h = n;\n    original.w = n;\n\n    uint64_t seed64 = 1234567891234567ULL;\n    for (int i = 0; i < n * n; ++i) {\n        int x;\n        cin >> x;\n        original.a[i] = (unsigned char)x;\n        seed64 ^= (uint64_t)(x + 1) + 0x9e3779b97f4a7c15ULL + (seed64 << 6) + (seed64 >> 2);\n    }\n\n    memset(origAdj, 0, sizeof(origAdj));\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            int idx = i * n + j;\n            int c = original.a[idx];\n\n            if (i == 0 || i == n - 1 || j == 0 || j == n - 1) {\n                origAdj[c][0] = origAdj[0][c] = true;\n            }\n            if (i + 1 < n) {\n                int d = original.a[idx + n];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n            if (j + 1 < n) {\n                int d = original.a[idx + 1];\n                if (c != d) origAdj[c][d] = origAdj[d][c] = true;\n            }\n        }\n    }\n\n    for (int i = 0; i <= m; ++i) distColor[i] = INF_INT;\n    queue<int> q;\n    distColor[0] = 0;\n    q.push(0);\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        for (int to = 0; to <= m; ++to) {\n            if (!origAdj[v][to]) continue;\n            if (distColor[to] != INF_INT) continue;\n            distColor[to] = distColor[v] + 1;\n            q.push(to);\n        }\n    }\n\n    for (int i = 0; i <= m; ++i) {\n        int dg = 0;\n        for (int j = 0; j <= m; ++j) if (origAdj[i][j]) ++dg;\n        degColor[i] = dg;\n    }\n\n    int maxDepth = 0;\n    for (int c = 1; c <= m; ++c) maxDepth = max(maxDepth, distColor[c]);\n    depthGroups.assign(maxDepth + 1, {});\n    for (int c = 1; c <= m; ++c) depthGroups[distColor[c]].push_back(c);\n\n    compute_stats(original);\n\n    mt19937 rng((uint32_t)(seed64 ^ (seed64 >> 32)));\n\n    auto start = Clock::now();\n    auto deadline = start + chrono::milliseconds(1930);\n\n    auto sub_deadline = [&](int ms) -> Clock::time_point {\n        return min(deadline, Clock::now() + chrono::milliseconds(ms));\n    };\n\n    Board best = original;\n    Board cur = original;\n\n    // Initial diversified passes.\n    vector<int> initK = {1, 2, 4, 6};\n    for (int k : initK) {\n        if (Clock::now() >= deadline) break;\n        Board cand = shrink_pass(original, rng, sub_deadline(105), k);\n        cand = shave_pass(cand, rng, sub_deadline(120));\n        cand = shrink_pass(cand, rng, sub_deadline(65), k + 1);\n        if (better_board(cand, best)) best = cand;\n    }\n    cur = best;\n\n    int iter = 0;\n    while (Clock::now() < deadline) {\n        Board seed;\n        if (iter % 6 == 0) seed = original;\n        else if (iter % 6 == 1 || iter % 6 == 2) seed = best;\n        else seed = cur;\n\n        Board cand = seed;\n        int k1 = 1 + (rng() % 7);\n        int k2 = 1 + (rng() % 7);\n\n        if (iter % 2 == 0) {\n            cand = shrink_pass(cand, rng, sub_deadline(58), k1);\n            cand = shave_pass(cand, rng, sub_deadline(82));\n            cand = shrink_pass(cand, rng, sub_deadline(48), k2);\n        } else {\n            cand = shave_pass(cand, rng, sub_deadline(70));\n            cand = shrink_pass(cand, rng, sub_deadline(68), k1);\n            cand = shave_pass(cand, rng, sub_deadline(42));\n        }\n\n        if (better_board(cand, best)) best = cand;\n        if (better_board(cand, cur) || iter % 3 == 0) cur = cand;\n        else cur = best;\n\n        ++iter;\n    }\n\n    crop_zero_border(best);\n    compute_stats(best);\n\n    vector<vector<int>> out(n, vector<int>(n, 0));\n    for (int i = 0; i < best.h; ++i) {\n        for (int j = 0; j < best.w; ++j) {\n            out[i][j] = best.a[i * best.w + j];\n        }\n    }\n\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < n; ++j) {\n            if (j) cout << ' ';\n            cout << out[i][j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, D, Q;\n    int used = 0;\n\n    vector<int> cost_ins;\n    vector<vector<signed char>> itemMemo;\n    vector<vector<signed char>> blockMemo;\n\n    vector<vector<int>> blocks;\n    vector<vector<int>> bins;\n\n    vector<int> order_est;\n    vector<int> rank_pos;\n    vector<double> pweight;\n    vector<double> est_load;\n    vector<double> harm;\n\n    int M = 1;\n    int baseSize = 1;\n    int remBlocks = 0;\n    int iterBound = 0;\n    int reserve_balance = 0;\n    int actual_assigned = 0;\n\n    uint64_t base_seed = 0;\n\n    static signed char enc(char c) {\n        if (c == '>') return 1;\n        if (c == '<') return -1;\n        return 2;\n    }\n    static char dec(signed char v) {\n        if (v == 1) return '>';\n        if (v == -1) return '<';\n        return '=';\n    }\n    static char rev(char c) {\n        if (c == '>') return '<';\n        if (c == '<') return '>';\n        return '=';\n    }\n\n    int ceil_log2_int(int x) {\n        if (x <= 1) return 0;\n        int p = 0, y = 1;\n        while (y < x) y <<= 1, ++p;\n        return p;\n    }\n\n    char ask_sets(const vector<int>& L, const vector<int>& R) {\n        if (used >= Q) exit(0);\n\n        cout << L.size() << ' ' << R.size();\n        for (int x : L) cout << ' ' << x;\n        for (int x : R) cout << ' ' << x;\n        cout << '\\n' << flush;\n\n        string s;\n        if (!(cin >> s)) exit(0);\n        ++used;\n        return s[0];\n    }\n\n    char cmp_item(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = itemMemo[a][b];\n        if (m != 0) return dec(m);\n        char s = ask_sets(vector<int>{a}, vector<int>{b});\n        itemMemo[a][b] = enc(s);\n        itemMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    char cmp_block(int a, int b) {\n        if (a == b) return '=';\n        signed char &m = blockMemo[a][b];\n        if (m != 0) return dec(m);\n\n        vector<int> L, R;\n        L.reserve(baseSize);\n        R.reserve(baseSize);\n        for (int i = 0; i < baseSize; ++i) L.push_back(blocks[a][i]);\n        for (int i = 0; i < baseSize; ++i) R.push_back(blocks[b][i]);\n\n        char s = ask_sets(L, R);\n        blockMemo[a][b] = enc(s);\n        blockMemo[b][a] = enc(rev(s));\n        return s;\n    }\n\n    void precompute_costs() {\n        cost_ins.assign(N + 1, 0);\n        for (int n = 1; n <= N; ++n) {\n            cost_ins[n] = cost_ins[n - 1] + ceil_log2_int(n);\n        }\n\n        harm.assign(N + 1, 0.0);\n        for (int i = 1; i <= N; ++i) harm[i] = harm[i - 1] + 1.0 / i;\n    }\n\n    int scheme_cost(int m) {\n        int base = N / m;\n        int rem = N % m;\n        long long c = 1LL * rem * cost_ins[base + 1]\n                    + 1LL * (m - rem) * cost_ins[base]\n                    + cost_ins[m];\n        return (int)c;\n    }\n\n    int estimated_actual_place_count(int extra_queries) {\n        if (D <= 1 || extra_queries <= 0) return 0;\n\n        int simple = extra_queries / max(1, D - 1);\n\n        int h = max(1, ceil_log2_int(D));\n        int tourn = 0;\n        if (extra_queries >= D - 1) {\n            tourn = (extra_queries - (D - 1)) / h;\n        }\n\n        return max(simple, tourn);\n    }\n\n    void choose_scheme() {\n        iterBound = 2 * (D - 1) + 6 + 2 * ceil_log2_int(N);\n        reserve_balance = min(Q, 2 * iterBound);\n\n        double bestScore = -1e100;\n        int bestM = 1;\n\n        for (int m = 1; m <= N; ++m) {\n            int c = scheme_cost(m);\n            if (c > Q) continue;\n            int extra = max(0, Q - c - reserve_balance);\n            double place_cnt = min<double>(N - D, estimated_actual_place_count(extra));\n            double score = m + 1.0 * place_cnt;\n            if (score > bestScore + 1e-12 || (abs(score - bestScore) <= 1e-12 && m > bestM)) {\n                bestScore = score;\n                bestM = m;\n            }\n        }\n\n        M = bestM;\n        baseSize = N / M;\n        remBlocks = N % M;\n\n        // Conservative exact-sort fallback:\n        // if full sorting is affordable and not much more expensive than the chosen scheme,\n        // use the exact order.\n        int fullCost = cost_ins[N];\n        int chosenCost = scheme_cost(M);\n        if (fullCost + reserve_balance <= Q) {\n            int overhead = fullCost - chosenCost;\n            int extraFull = Q - fullCost - reserve_balance;\n            if (overhead <= 100 || (overhead <= 160 && extraFull >= max(D, 12))) {\n                M = 1;\n                baseSize = N;\n                remBlocks = 0;\n            }\n        }\n    }\n\n    vector<int> sort_items_by_weight(const vector<int>& arr) {\n        vector<int> res;\n        res.reserve(arr.size());\n        for (int x : arr) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_item(x, res[mid]);\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, x);\n        }\n        return res;\n    }\n\n    vector<int> sort_block_ids(const vector<int>& ids) {\n        vector<int> res;\n        res.reserve(ids.size());\n        for (int id : ids) {\n            int l = 0, r = (int)res.size();\n            while (l < r) {\n                int mid = (l + r) >> 1;\n                char s = cmp_block(id, res[mid]);\n                if (s == '>') r = mid;\n                else l = mid + 1;\n            }\n            res.insert(res.begin() + l, id);\n        }\n        return res;\n    }\n\n    double inv_norm(double p) {\n        p = min(1.0 - 1e-12, max(1e-12, p));\n\n        static const double a1 = -3.969683028665376e+01;\n        static const double a2 =  2.209460984245205e+02;\n        static const double a3 = -2.759285104469687e+02;\n        static const double a4 =  1.383577518672690e+02;\n        static const double a5 = -3.066479806614716e+01;\n        static const double a6 =  2.506628277459239e+00;\n\n        static const double b1 = -5.447609879822406e+01;\n        static const double b2 =  1.615858368580409e+02;\n        static const double b3 = -1.556989798598866e+02;\n        static const double b4 =  6.680131188771972e+01;\n        static const double b5 = -1.328068155288572e+01;\n\n        static const double c1 = -7.784894002430293e-03;\n        static const double c2 = -3.223964580411365e-01;\n        static const double c3 = -2.400758277161838e+00;\n        static const double c4 = -2.549732539343734e+00;\n        static const double c5 =  4.374664141464968e+00;\n        static const double c6 =  2.938163982698783e+00;\n\n        static const double d1 =  7.784695709041462e-03;\n        static const double d2 =  3.224671290700398e-01;\n        static const double d3 =  2.445134137142996e+00;\n        static const double d4 =  3.754408661907416e+00;\n\n        const double plow = 0.02425;\n        const double phigh = 1.0 - plow;\n\n        if (p < plow) {\n            double q = sqrt(-2.0 * log(p));\n            return (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /\n                   ((((d1 * q + d2) * q + d3) * q + d4) * q + 1.0);\n        }\n        if (p > phigh) {\n            double q = sqrt(-2.0 * log(1.0 - p));\n            return -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /\n                    ((((d1 * q + d2) * q + d3) * q + d4) * q + 1.0);\n        }\n        double q = p - 0.5;\n        double r = q * q;\n        return (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q /\n               (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1.0);\n    }\n\n    void build_estimated_order() {\n        vector<int> items(N);\n        iota(items.begin(), items.end(), 0);\n\n        blocks.clear();\n        int cur = 0;\n        for (int i = 0; i < M; ++i) {\n            int sz = baseSize + (i < remBlocks ? 1 : 0);\n            vector<int> blk;\n            blk.reserve(sz);\n            for (int j = 0; j < sz; ++j) blk.push_back(items[cur++]);\n            blocks.push_back(sort_items_by_weight(blk));\n        }\n\n        blockMemo.assign(M, vector<signed char>(M, 0));\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        ids = sort_block_ids(ids);\n\n        struct Cand {\n            double key;\n            int block_rank;\n            int pos_in_block;\n            int item;\n        };\n        vector<Cand> cand;\n        cand.reserve(N);\n\n        double alpha = 0.85;\n        double denom = sqrt((double)max(1, baseSize));\n\n        for (int br = 0; br < M; ++br) {\n            int id = ids[br];\n            int s = (int)blocks[id].size();\n\n            double p = (M - br - 0.5) / (double)M;\n            double z = inv_norm(p);\n            double scale = exp(alpha * z / denom);\n\n            for (int j = 0; j < s; ++j) {\n                int x = blocks[id][j];\n                double inside = harm[s] - harm[j];\n                double key = inside * scale;\n                cand.push_back({key, br, j, x});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [&](const Cand& a, const Cand& b) {\n            if (fabs(a.key - b.key) > 1e-12) return a.key > b.key;\n            if (a.block_rank != b.block_rank) return a.block_rank < b.block_rank;\n            if (a.pos_in_block != b.pos_in_block) return a.pos_in_block < b.pos_in_block;\n            return a.item < b.item;\n        });\n\n        order_est.clear();\n        order_est.reserve(N);\n        rank_pos.assign(N, 0);\n        pweight.assign(N, 0.0);\n\n        for (int i = 0; i < N; ++i) {\n            int x = cand[i].item;\n            order_est.push_back(x);\n            rank_pos[x] = i;\n            pweight[x] = harm[N] - harm[i];\n        }\n    }\n\n    struct MinTournament {\n        Solver* S;\n        int D, SZ;\n        vector<int> tr;\n\n        MinTournament(Solver* solver, int d): S(solver), D(d) {\n            SZ = 1;\n            while (SZ < D) SZ <<= 1;\n            tr.assign(2 * SZ, -1);\n        }\n\n        int better(int a, int b) {\n            if (a == -1) return b;\n            if (b == -1) return a;\n            char s = S->ask_sets(S->bins[a], S->bins[b]);\n            if (s == '<') return a;\n            if (s == '>') return b;\n            return min(a, b);\n        }\n\n        void build() {\n            for (int i = 0; i < D; ++i) tr[SZ + i] = i;\n            for (int i = D; i < SZ; ++i) tr[SZ + i] = -1;\n            for (int i = SZ - 1; i >= 1; --i) tr[i] = better(tr[i << 1], tr[i << 1 | 1]);\n        }\n\n        int winner() const { return tr[1]; }\n\n        void update(int idx) {\n            int p = SZ + idx;\n            tr[p] = idx;\n            p >>= 1;\n            while (p >= 1) {\n                tr[p] = better(tr[p << 1], tr[p << 1 | 1]);\n                p >>= 1;\n            }\n        }\n    };\n\n    int actual_lightest_bin_simple() {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            char s = ask_sets(bins[i], bins[best]);\n            if (s == '<') best = i;\n        }\n        return best;\n    }\n\n    int pseudo_lightest_bin_of(const vector<vector<int>>& B, const vector<double>& L) const {\n        int best = 0;\n        for (int i = 1; i < D; ++i) {\n            if (L[i] < L[best] - 1e-12) best = i;\n            else if (fabs(L[i] - L[best]) <= 1e-12) {\n                if (B[i].size() < B[best].size()) best = i;\n                else if (B[i].size() == B[best].size() && i < best) best = i;\n            }\n        }\n        return best;\n    }\n\n    void insert_sorted_bin_to(vector<vector<int>>& B, int b, int item) const {\n        auto &v = B[b];\n        int rk = rank_pos[item];\n        auto it = lower_bound(v.begin(), v.end(), rk,\n                              [&](int lhs_item, int rhs_rank) {\n                                  return rank_pos[lhs_item] < rhs_rank;\n                              });\n        v.insert(it, item);\n    }\n\n    void insert_sorted_bin(int b, int item) {\n        insert_sorted_bin_to(bins, b, item);\n    }\n\n    double objective_of(const vector<double>& L) const {\n        double s = 0.0;\n        for (double x : L) s += x * x;\n        return s;\n    }\n\n    vector<int> sorted_bins_by_load(const vector<vector<int>>& B, const vector<double>& L) const {\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (fabs(L[a] - L[b]) > 1e-12) return L[a] < L[b];\n            if (B[a].size() != B[b].size()) return B[a].size() < B[b].size();\n            return a < b;\n        });\n        return ord;\n    }\n\n    void pseudo_improve_hl_state(vector<vector<int>>& B, vector<double>& L, int max_iter) {\n        for (int iter = 0; iter < max_iter; ++iter) {\n            int h = 0, l = 0;\n            for (int i = 1; i < D; ++i) {\n                if (L[i] > L[h]) h = i;\n                if (L[i] < L[l]) l = i;\n            }\n            if (h == l) break;\n\n            double lh = L[h], ll = L[l];\n            double bestDelta = -1e-12;\n            int bestType = 0;\n            int bestI = -1, bestJ = -1;\n\n            if ((int)B[h].size() > 1) {\n                for (int i = 0; i < (int)B[h].size(); ++i) {\n                    int x = B[h][i];\n                    double w = pweight[x];\n                    double nh = lh - w;\n                    double nl = ll + w;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 1;\n                        bestI = i;\n                    }\n                }\n            }\n\n            for (int i = 0; i < (int)B[h].size(); ++i) {\n                int x = B[h][i];\n                double wx = pweight[x];\n                for (int j = 0; j < (int)B[l].size(); ++j) {\n                    int y = B[l][j];\n                    double wy = pweight[y];\n                    double nh = lh - wx + wy;\n                    double nl = ll - wy + wx;\n                    double delta = nh * nh + nl * nl - lh * lh - ll * ll;\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestType = 2;\n                        bestI = i;\n                        bestJ = j;\n                    }\n                }\n            }\n\n            if (bestType == 0) break;\n\n            if (bestType == 1) {\n                int x = B[h][bestI];\n                B[h].erase(B[h].begin() + bestI);\n                insert_sorted_bin_to(B, l, x);\n                L[h] -= pweight[x];\n                L[l] += pweight[x];\n            } else {\n                int x = B[h][bestI];\n                int y = B[l][bestJ];\n                B[h].erase(B[h].begin() + bestI);\n                B[l].erase(B[l].begin() + bestJ);\n                insert_sorted_bin_to(B, h, y);\n                insert_sorted_bin_to(B, l, x);\n                L[h] += pweight[y] - pweight[x];\n                L[l] += pweight[x] - pweight[y];\n            }\n        }\n    }\n\n    void pseudo_improve_global_state(vector<vector<int>>& B, vector<double>& L, int max_iter) {\n        auto sq = [&](double x) { return x * x; };\n\n        for (int iter = 0; iter < max_iter; ++iter) {\n            double bestDelta = -1e-12;\n            int bestType = 0;\n            int A = -1, B2 = -1, IA = -1, IB = -1;\n\n            for (int a = 0; a < D; ++a) {\n                if ((int)B[a].size() <= 1) continue;\n                double la = L[a];\n                for (int ia = 0; ia < (int)B[a].size(); ++ia) {\n                    int x = B[a][ia];\n                    double wx = pweight[x];\n                    for (int b = 0; b < D; ++b) if (a != b) {\n                        double lb = L[b];\n                        double delta = sq(la - wx) + sq(lb + wx) - sq(la) - sq(lb);\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestType = 1;\n                            A = a; B2 = b; IA = ia; IB = -1;\n                        }\n                    }\n                }\n            }\n\n            for (int a = 0; a < D; ++a) {\n                double la = L[a];\n                for (int b = a + 1; b < D; ++b) {\n                    double lb = L[b];\n                    for (int ia = 0; ia < (int)B[a].size(); ++ia) {\n                        int x = B[a][ia];\n                        double wx = pweight[x];\n                        for (int ib = 0; ib < (int)B[b].size(); ++ib) {\n                            int y = B[b][ib];\n                            double wy = pweight[y];\n                            double delta = sq(la - wx + wy) + sq(lb - wy + wx) - sq(la) - sq(lb);\n                            if (delta < bestDelta) {\n                                bestDelta = delta;\n                                bestType = 2;\n                                A = a; B2 = b; IA = ia; IB = ib;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (bestType == 0) break;\n\n            if (bestType == 1) {\n                int x = B[A][IA];\n                B[A].erase(B[A].begin() + IA);\n                insert_sorted_bin_to(B, B2, x);\n                L[A] -= pweight[x];\n                L[B2] += pweight[x];\n            } else {\n                int x = B[A][IA];\n                int y = B[B2][IB];\n                B[A].erase(B[A].begin() + IA);\n                B[B2].erase(B[B2].begin() + IB);\n                insert_sorted_bin_to(B, A, y);\n                insert_sorted_bin_to(B, B2, x);\n                L[A] += pweight[y] - pweight[x];\n                L[B2] += pweight[x] - pweight[y];\n            }\n        }\n    }\n\n    void complete_remaining_multistart(const vector<vector<int>>& baseBins,\n                                       const vector<double>& baseLoads,\n                                       const vector<int>& remItems) {\n        if (remItems.empty()) {\n            bins = baseBins;\n            est_load = baseLoads;\n            return;\n        }\n\n        auto do_seq = [&](vector<vector<int>>& B, vector<double>& L) {\n            for (int x : remItems) {\n                int b = pseudo_lightest_bin_of(B, L);\n                B[b].push_back(x);\n                L[b] += pweight[x];\n            }\n        };\n\n        auto do_batchD = [&](vector<vector<int>>& B, vector<double>& L) {\n            int ptr = 0;\n            while (ptr < (int)remItems.size()) {\n                int k = min(D, (int)remItems.size() - ptr);\n                vector<int> ord = sorted_bins_by_load(B, L);\n                for (int j = 0; j < k; ++j) {\n                    int x = remItems[ptr++];\n                    int b = ord[j];\n                    B[b].push_back(x);\n                    L[b] += pweight[x];\n                }\n            }\n        };\n\n        auto do_snake2D = [&](vector<vector<int>>& B, vector<double>& L) {\n            int ptr = 0;\n            while (ptr < (int)remItems.size()) {\n                vector<int> ord = sorted_bins_by_load(B, L);\n                int k1 = min(D, (int)remItems.size() - ptr);\n                for (int j = 0; j < k1; ++j) {\n                    int x = remItems[ptr++];\n                    int b = ord[j];\n                    B[b].push_back(x);\n                    L[b] += pweight[x];\n                }\n                int k2 = min(D, (int)remItems.size() - ptr);\n                for (int j = 0; j < k2; ++j) {\n                    int x = remItems[ptr++];\n                    int b = ord[k2 - 1 - j];\n                    B[b].push_back(x);\n                    L[b] += pweight[x];\n                }\n            }\n        };\n\n        auto do_random_topk = [&](vector<vector<int>>& B, vector<double>& L, int topk, uint64_t seed) {\n            mt19937_64 rng(seed);\n            for (int x : remItems) {\n                vector<int> ord = sorted_bins_by_load(B, L);\n                int k = min(topk, D);\n                int pick = 0;\n                if (k >= 2) {\n                    uniform_int_distribution<int> dist(0, k - 1);\n                    pick = dist(rng);\n                }\n                int b = ord[pick];\n                B[b].push_back(x);\n                L[b] += pweight[x];\n            }\n        };\n\n        auto do_noisy = [&](vector<vector<int>>& B, vector<double>& L, double lambda, uint64_t seed) {\n            mt19937_64 rng(seed);\n            double avgw = 0.0;\n            for (int x : remItems) avgw += pweight[x];\n            avgw /= max<int>(1, remItems.size());\n            uniform_real_distribution<double> dist(0.0, 1.0);\n\n            for (int x : remItems) {\n                int best = 0;\n                double bestScore = 1e100;\n                for (int b = 0; b < D; ++b) {\n                    double score = L[b] + lambda * avgw * dist(rng) + 1e-4 * (double)B[b].size();\n                    if (score < bestScore) {\n                        bestScore = score;\n                        best = b;\n                    }\n                }\n                B[best].push_back(x);\n                L[best] += pweight[x];\n            }\n        };\n\n        double bestObj = 1e300;\n        vector<vector<int>> bestBins;\n        vector<double> bestLoads;\n\n        int mild_hl = 250;\n        int mild_gl = 25;\n\n        int methods = 6;\n        for (int method = 0; method < methods; ++method) {\n            vector<vector<int>> B = baseBins;\n            vector<double> L = baseLoads;\n\n            if (method == 0) {\n                do_seq(B, L);\n            } else if (method == 1) {\n                do_batchD(B, L);\n            } else if (method == 2) {\n                do_snake2D(B, L);\n            } else if (method == 3) {\n                do_random_topk(B, L, 2, base_seed + 1001);\n            } else if (method == 4) {\n                do_random_topk(B, L, min(3, D), base_seed + 2003);\n            } else if (method == 5) {\n                do_noisy(B, L, 0.08, base_seed + 3007);\n            }\n\n            pseudo_improve_hl_state(B, L, mild_hl);\n            pseudo_improve_global_state(B, L, mild_gl);\n\n            double obj = objective_of(L);\n            double mx = *max_element(L.begin(), L.end());\n            double mn = *min_element(L.begin(), L.end());\n            obj += 1e-9 * (mx - mn);\n\n            if (obj < bestObj) {\n                bestObj = obj;\n                bestBins.swap(B);\n                bestLoads.swap(L);\n            }\n        }\n\n        bins.swap(bestBins);\n        est_load.swap(bestLoads);\n    }\n\n    void assign_initial() {\n        bins.assign(D, {});\n        est_load.assign(D, 0.0);\n        actual_assigned = 0;\n\n        int ptr = 0;\n        for (int b = 0; b < D; ++b) {\n            int x = order_est[ptr++];\n            bins[b].push_back(x);\n            est_load[b] += pweight[x];\n        }\n\n        int rem = max(0, Q - used - reserve_balance);\n        int simpleK = rem / max(1, D - 1);\n\n        int h = max(1, ceil_log2_int(D));\n        int tournK = 0;\n        if (rem >= D - 1) {\n            tournK = (rem - (D - 1)) / h;\n        }\n\n        int remaining_items = N - ptr;\n        bool use_tournament = false;\n        int K = 0;\n\n        if (tournK > simpleK && tournK >= 2) {\n            use_tournament = true;\n            K = min(remaining_items, tournK);\n        } else {\n            K = min(remaining_items, simpleK);\n        }\n\n        if (use_tournament && K > 0) {\n            MinTournament tour(this, D);\n            tour.build();\n            for (int t = 0; t < K; ++t) {\n                int x = order_est[ptr++];\n                int b = tour.winner();\n                bins[b].push_back(x);\n                est_load[b] += pweight[x];\n                tour.update(b);\n                ++actual_assigned;\n            }\n        } else {\n            for (int t = 0; t < K; ++t) {\n                int x = order_est[ptr++];\n                int b = actual_lightest_bin_simple();\n                bins[b].push_back(x);\n                est_load[b] += pweight[x];\n                ++actual_assigned;\n            }\n        }\n\n        vector<vector<int>> baseBins = bins;\n        vector<double> baseLoads = est_load;\n        vector<int> remItems;\n        remItems.reserve(N - ptr);\n        while (ptr < N) remItems.push_back(order_est[ptr++]);\n\n        complete_remaining_multistart(baseBins, baseLoads, remItems);\n    }\n\n    void pseudo_improve_hl(int max_iter) {\n        pseudo_improve_hl_state(bins, est_load, max_iter);\n    }\n\n    void pseudo_improve_global(int max_iter) {\n        pseudo_improve_global_state(bins, est_load, max_iter);\n    }\n\n    pair<int, int> actual_extremes() {\n        vector<vector<signed char>> memo(D, vector<signed char>(D, 0));\n        auto cmpBin = [&](int a, int b) -> char {\n            if (a == b) return '=';\n            signed char &m = memo[a][b];\n            if (m != 0) return dec(m);\n            char s = ask_sets(bins[a], bins[b]);\n            memo[a][b] = enc(s);\n            memo[b][a] = enc(rev(s));\n            return s;\n        };\n\n        int hi = 0, lo = 0;\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, hi) == '>') hi = i;\n        }\n        for (int i = 1; i < D; ++i) {\n            if (cmpBin(i, lo) == '<') lo = i;\n        }\n        return {hi, lo};\n    }\n\n    int select_move_candidate(int H, int L) {\n        int m = (int)bins[H].size();\n        if (m <= 1) return -1;\n\n        vector<signed char> memo(m, 0);\n        auto test = [&](int idx) -> char {\n            if (memo[idx] != 0) return dec(memo[idx]);\n            vector<int> left, right;\n            left.reserve(m - 1);\n            right.reserve(bins[L].size() + 1);\n            for (int i = 0; i < m; ++i) if (i != idx) left.push_back(bins[H][i]);\n            for (int x : bins[L]) right.push_back(x);\n            right.push_back(bins[H][idx]);\n            char s = ask_sets(left, right);\n            memo[idx] = enc(s);\n            return s;\n        };\n\n        char s0 = test(0);\n        if (s0 == '>' || s0 == '=') return 0;\n\n        char sl = test(m - 1);\n        if (sl == '=') return m - 1;\n        if (sl == '<') return -1;\n\n        int lo = 0, hi = m - 1;\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '<') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double v1 = fabs(diff - 2.0 * pweight[bins[H][lo]]);\n        double v2 = fabs(diff - 2.0 * pweight[bins[H][hi]]);\n        return (v2 < v1 ? hi : lo);\n    }\n\n    int select_swap_candidate(int H, int L) {\n        int xidx = (int)bins[H].size() - 1;\n        int x = bins[H][xidx];\n        int rkx = rank_pos[x];\n\n        int n = (int)bins[L].size();\n        int first = 0;\n        while (first < n && rank_pos[bins[L][first]] < rkx) ++first;\n        if (first == n) return -1;\n\n        vector<signed char> memo(n, 0);\n        auto test = [&](int yidx) -> char {\n            if (memo[yidx] != 0) return dec(memo[yidx]);\n            vector<int> left, right;\n            left.reserve(bins[H].size());\n            right.reserve(bins[L].size());\n            for (int i = 0; i < (int)bins[H].size(); ++i) {\n                if (i != xidx) left.push_back(bins[H][i]);\n            }\n            left.push_back(bins[L][yidx]);\n\n            for (int i = 0; i < (int)bins[L].size(); ++i) {\n                if (i != yidx) right.push_back(bins[L][i]);\n            }\n            right.push_back(x);\n\n            char s = ask_sets(left, right);\n            memo[yidx] = enc(s);\n            return s;\n        };\n\n        char sf = test(first);\n        if (sf == '=') return first;\n        if (sf == '<') return -1;\n\n        char sl = test(n - 1);\n        if (sl == '=') return n - 1;\n        if (sl == '>') return n - 1;\n\n        int lo = first, hi = n - 1;\n        while (hi - lo > 1) {\n            int mid = (lo + hi) >> 1;\n            char s = test(mid);\n            if (s == '=') return mid;\n            if (s == '>') lo = mid;\n            else hi = mid;\n        }\n\n        double diff = est_load[H] - est_load[L];\n        double wx = pweight[x];\n        double d1 = fabs(diff - 2.0 * (wx - pweight[bins[L][lo]]));\n        double d2 = fabs(diff - 2.0 * (wx - pweight[bins[L][hi]]));\n        return (d2 < d1 ? hi : lo);\n    }\n\n    void apply_move(int H, int L, int idx) {\n        int x = bins[H][idx];\n        bins[H].erase(bins[H].begin() + idx);\n        insert_sorted_bin(L, x);\n        est_load[H] -= pweight[x];\n        est_load[L] += pweight[x];\n    }\n\n    void apply_swap(int H, int L, int yidx) {\n        int xidx = (int)bins[H].size() - 1;\n        int x = bins[H][xidx];\n        int y = bins[L][yidx];\n\n        bins[H].erase(bins[H].begin() + xidx);\n        bins[L].erase(bins[L].begin() + yidx);\n        insert_sorted_bin(H, y);\n        insert_sorted_bin(L, x);\n\n        est_load[H] += pweight[y] - pweight[x];\n        est_load[L] += pweight[x] - pweight[y];\n    }\n\n    void actual_improve_full() {\n        while (used + iterBound <= Q) {\n            auto [H, L] = actual_extremes();\n            if (H == L) break;\n\n            bool changed = false;\n\n            if ((int)bins[H].size() > 1) {\n                int idx = select_move_candidate(H, L);\n                if (idx != -1) {\n                    apply_move(H, L, idx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) {\n                int yidx = select_swap_candidate(H, L);\n                if (yidx != -1) {\n                    apply_swap(H, L, yidx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> topk_bins_by_est(bool largest, int k) {\n        vector<int> ord(D);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (fabs(est_load[a] - est_load[b]) > 1e-12) {\n                if (largest) return est_load[a] > est_load[b];\n                else return est_load[a] < est_load[b];\n            }\n            if (bins[a].size() != bins[b].size()) {\n                if (largest) return bins[a].size() > bins[b].size();\n                else return bins[a].size() < bins[b].size();\n            }\n            return a < b;\n        });\n        if ((int)ord.size() > k) ord.resize(k);\n        return ord;\n    }\n\n    int actual_best_in_subset(const vector<int>& cand, bool wantMax, int exclude = -1) {\n        int best = -1;\n        for (int x : cand) {\n            if (x == exclude) continue;\n            if (best == -1) {\n                best = x;\n                continue;\n            }\n            char s = ask_sets(bins[x], bins[best]);\n            if (wantMax) {\n                if (s == '>' || (s == '=' && x < best)) best = x;\n            } else {\n                if (s == '<' || (s == '=' && x < best)) best = x;\n            }\n        }\n        return best;\n    }\n\n    void actual_improve_tail() {\n        int estOnlyBound = 2 * (2 + ceil_log2_int(N)) + 4;\n        auto subsetBound = [&](int k) {\n            return 2 * max(0, k - 1) + estOnlyBound;\n        };\n\n        while (true) {\n            int modeK = 1;\n            if (D >= 4 && used + subsetBound(4) <= Q) modeK = 4;\n            else if (D >= 3 && used + subsetBound(3) <= Q) modeK = 3;\n            else if (D >= 2 && used + subsetBound(2) <= Q) modeK = 2;\n            else if (used + estOnlyBound <= Q) modeK = 1;\n            else break;\n\n            int H = 0, L = 0;\n\n            if (modeK == 1) {\n                for (int i = 1; i < D; ++i) {\n                    if (est_load[i] > est_load[H]) H = i;\n                    if (est_load[i] < est_load[L]) L = i;\n                }\n            } else {\n                vector<int> heavyCand = topk_bins_by_est(true, modeK);\n                vector<int> lightCand = topk_bins_by_est(false, modeK);\n\n                H = actual_best_in_subset(heavyCand, true, -1);\n                L = actual_best_in_subset(lightCand, false, H);\n                if (L == -1) L = actual_best_in_subset(lightCand, false, -1);\n\n                if (H == -1 || L == -1 || H == L) {\n                    H = 0;\n                    L = 0;\n                    for (int i = 1; i < D; ++i) {\n                        if (est_load[i] > est_load[H]) H = i;\n                        if (est_load[i] < est_load[L]) L = i;\n                    }\n                }\n            }\n\n            if (H == L) break;\n\n            bool changed = false;\n\n            if ((int)bins[H].size() > 1) {\n                int idx = select_move_candidate(H, L);\n                if (idx != -1) {\n                    apply_move(H, L, idx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) {\n                int yidx = select_swap_candidate(H, L);\n                if (yidx != -1) {\n                    apply_swap(H, L, yidx);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    void actual_improve() {\n        actual_improve_full();\n        actual_improve_tail();\n    }\n\n    void fill_dummy_queries() {\n        while (used < Q) {\n            ask_sets(vector<int>{0}, vector<int>{1});\n        }\n    }\n\n    void output_answer() {\n        vector<int> ans(N, 0);\n        for (int b = 0; b < D; ++b) {\n            for (int x : bins[b]) ans[x] = b;\n        }\n        for (int i = 0; i < N; ++i) {\n            if (i) cout << ' ';\n            cout << ans[i];\n        }\n        cout << '\\n' << flush;\n    }\n\n    void solve() {\n        cin >> N >> D >> Q;\n        base_seed = 1469598103934665603ULL;\n        base_seed ^= (uint64_t)N + 0x9e3779b97f4a7c15ULL + (base_seed << 6) + (base_seed >> 2);\n        base_seed ^= (uint64_t)D + 0x9e3779b97f4a7c15ULL + (base_seed << 6) + (base_seed >> 2);\n        base_seed ^= (uint64_t)Q + 0x9e3779b97f4a7c15ULL + (base_seed << 6) + (base_seed >> 2);\n\n        itemMemo.assign(N, vector<signed char>(N, 0));\n\n        precompute_costs();\n        choose_scheme();\n        build_estimated_order();\n        assign_initial();\n\n        int hl_iters = 1500;\n        int global_iters = 120;\n        int rem_items = max(1, N - D);\n\n        if (actual_assigned * 4 >= 3 * rem_items) {\n            hl_iters = 350;\n            global_iters = 50;\n        } else if (actual_assigned * 2 >= rem_items) {\n            hl_iters = 800;\n            global_iters = 80;\n        }\n\n        pseudo_improve_hl(hl_iters);\n        pseudo_improve_global(global_iters);\n        actual_improve();\n        fill_dummy_queries();\n        output_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NMAX = 200;\nstatic constexpr int MMAX = 10;\nstatic constexpr uint8_t REMOVED = 255;\nstatic constexpr int INF = 1e9;\n\nint N, M;\nchrono::steady_clock::time_point g_start;\ndouble g_deadline = 1.80;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\n\nstruct State {\n    uint8_t a[MMAX][NMAX];   // bottom -> top\n    uint8_t h[MMAX];\n    uint8_t st_of[NMAX + 1]; // stack id, or 255 if removed\n    uint8_t pos[NMAX + 1];   // position in stack\n    uint16_t cur;            // next box to remove\n};\n\nstruct Result {\n    int energy = INF;\n    vector<pair<int,int>> ops;\n};\n\nstruct Features {\n    int solo = 0;      // bad + seg\n    int bad = 0;       // non-record-minima from bottom\n    int seg = 0;       // forced future expensive moves in solo model\n    int empty = 0;     // number of empty stacks\n    int nextBlock = 0; // blockers above next target box\n};\n\nstruct AppendInfo {\n    int solo = 0;      // appendBad + appendSeg\n    int bad = 0;       // non-record-minima created inside appended segment\n    int seg = 0;       // segment overhead inside appended segment\n    int baseMin = 0;   // current minimum of destination before appending; larger is better\n};\n\nstruct Node {\n    State st;\n    int g;            // exact energy so far\n    int parent;       // index in nodes, -1 for root\n    uint8_t actionTo; // 1..M, 0 for root\n};\n\nstruct TempChild {\n    State st;\n    int g;\n    int lb;       // g + solo\n    int hval;     // heuristic score\n    int eval;     // g + hval\n\n    int empty;\n    int nextBlock;\n\n    int appSolo;\n    int appBad;\n    int baseMin;\n\n    int parent;\n    uint8_t actionTo;\n    uint16_t cur;\n};\n\nstruct Config {\n    int width;\n    int mode;\n    int greedyDepth;\n};\n\ninline void pop_all(State& st, vector<pair<int,int>>* ops = nullptr) {\n    while (st.cur <= N) {\n        uint8_t s = st.st_of[st.cur];\n        if (s == REMOVED) {\n            ++st.cur;\n            continue;\n        }\n        if ((int)st.pos[st.cur] + 1 != (int)st.h[s]) break;\n        if (ops) ops->push_back({(int)st.cur, 0});\n        --st.h[s];\n        st.st_of[st.cur] = REMOVED;\n        ++st.cur;\n    }\n}\n\ninline int move_blockers(State& st, int dst) {\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    int start = p + 1;\n    int len = (int)st.h[s] - start;\n    for (int i = start; i < (int)st.h[s]; ++i) {\n        uint8_t x = st.a[s][i];\n        st.a[dst][st.h[dst]] = x;\n        st.st_of[x] = (uint8_t)dst;\n        st.pos[x] = st.h[dst];\n        ++st.h[dst];\n    }\n    st.h[s] = (uint8_t)start;\n    return len;\n}\n\ninline Features calc_features(const State& st) {\n    Features f;\n    int recPos[NMAX];\n\n    if (st.cur <= N) {\n        uint8_t s = st.st_of[st.cur];\n        if (s != REMOVED) {\n            f.nextBlock = (int)st.h[s] - (int)st.pos[st.cur] - 1;\n        }\n    }\n\n    for (int i = 0; i < M; ++i) {\n        int h = st.h[i];\n        if (h == 0) {\n            ++f.empty;\n            continue;\n        }\n\n        int rc = 0;\n        int mn = N + 1;\n        for (int j = 0; j < h; ++j) {\n            int x = st.a[i][j];\n            if (x < mn) {\n                mn = x;\n                recPos[rc++] = j;\n            }\n        }\n\n        f.bad += h - rc;\n\n        for (int k = rc - 1; k >= 0; --k) {\n            int end = (k + 1 < rc ? recPos[k + 1] - 1 : h - 1);\n            int above = end - recPos[k];\n            if (above > 0) {\n                f.solo += above + 1;\n                ++f.seg;\n            }\n        }\n    }\n    return f;\n}\n\n// Local quality of appending the current moved segment to destination dst.\n// Smaller solo/bad is better; larger baseMin is better.\ninline AppendInfo calc_append_info(const State& st, int dst) {\n    AppendInfo res;\n    if (st.cur > N) return res;\n\n    int s = st.st_of[st.cur];\n    int p = st.pos[st.cur];\n    int start = p + 1;\n    int len = (int)st.h[s] - start;\n    if (len <= 0) return res;\n\n    int baseMin = N + 1;\n    for (int j = 0; j < (int)st.h[dst]; ++j) {\n        baseMin = min(baseMin, (int)st.a[dst][j]);\n    }\n    res.baseMin = baseMin;\n\n    int recPos[NMAX];\n    int rc = 0;\n    int mn = baseMin;\n    for (int j = start; j < (int)st.h[s]; ++j) {\n        int x = st.a[s][j];\n        if (x < mn) {\n            mn = x;\n            recPos[rc++] = j - start;\n        }\n    }\n\n    res.bad = len - rc;\n    int seg = 0;\n    for (int k = rc - 1; k >= 0; --k) {\n        int end = (k + 1 < rc ? recPos[k + 1] - 1 : len - 1);\n        if (end > recPos[k]) ++seg;\n    }\n    res.seg = seg;\n    res.solo = res.bad + res.seg;\n    return res;\n}\n\n// mode 0: bad + seg\n// mode 1: 2*bad + seg\n// mode 2: 3*bad + seg\n// mode 3: bad + 2*seg\n// mode 4: bad + 3*seg\ninline int estimate_from_features(const Features& f, int mode) {\n    switch (mode) {\n        case 0: return f.bad + f.seg;\n        case 1: return 2 * f.bad + f.seg;\n        case 2: return 3 * f.bad + f.seg;\n        case 3: return f.bad + 2 * f.seg;\n        case 4: return f.bad + 3 * f.seg;\n        default: return f.bad + f.seg;\n    }\n}\n\ninline int estimate(const State& st, int mode) {\n    return estimate_from_features(calc_features(st), mode);\n}\n\nint lookahead_cost(const State& st, int depth, int mode) {\n    if (st.cur > N) return 0;\n    if (elapsed_sec() > g_deadline) return estimate(st, mode);\n    if (depth == 0) return estimate(st, mode);\n\n    int cur = st.cur;\n    int s = st.st_of[cur];\n    int p = st.pos[cur];\n    if (p + 1 >= (int)st.h[s]) {\n        State nx = st;\n        pop_all(nx, nullptr);\n        return lookahead_cost(nx, depth, mode);\n    }\n\n    int len = (int)st.h[s] - p - 1;\n    int best = INF;\n\n    struct Cand {\n        int dst;\n        int hval;\n        int empty;\n        int nextBlock;\n        int appSolo;\n        int appBad;\n        int baseMin;\n        int nextCur;\n        State st;\n    };\n    Cand cand[MMAX - 1];\n    int cnt = 0;\n\n    for (int dst = 0; dst < M; ++dst) {\n        if (dst == s) continue;\n        cand[cnt].dst = dst;\n        cand[cnt].st = st;\n\n        AppendInfo ai = calc_append_info(st, dst);\n        move_blockers(cand[cnt].st, dst);\n        pop_all(cand[cnt].st, nullptr);\n\n        Features f = calc_features(cand[cnt].st);\n        cand[cnt].hval = estimate_from_features(f, mode);\n        cand[cnt].empty = f.empty;\n        cand[cnt].nextBlock = f.nextBlock;\n        cand[cnt].appSolo = ai.solo;\n        cand[cnt].appBad = ai.bad;\n        cand[cnt].baseMin = ai.baseMin;\n        cand[cnt].nextCur = cand[cnt].st.cur;\n        ++cnt;\n    }\n\n    array<int, MMAX - 1> ord{};\n    iota(ord.begin(), ord.begin() + cnt, 0);\n    sort(ord.begin(), ord.begin() + cnt, [&](int i, int j) {\n        if (cand[i].hval != cand[j].hval) return cand[i].hval < cand[j].hval;\n        if (cand[i].appSolo != cand[j].appSolo) return cand[i].appSolo < cand[j].appSolo;\n        if (cand[i].appBad != cand[j].appBad) return cand[i].appBad < cand[j].appBad;\n        if (cand[i].empty != cand[j].empty) return cand[i].empty > cand[j].empty;\n        if (cand[i].baseMin != cand[j].baseMin) return cand[i].baseMin > cand[j].baseMin;\n        if (cand[i].nextBlock != cand[j].nextBlock) return cand[i].nextBlock < cand[j].nextBlock;\n        if (cand[i].nextCur != cand[j].nextCur) return cand[i].nextCur > cand[j].nextCur;\n        return cand[i].dst < cand[j].dst;\n    });\n\n    int limit = cnt;\n    if (depth >= 3) limit = min(limit, 4);\n    else if (depth >= 2) limit = min(limit, 5);\n\n    for (int k = 0; k < limit; ++k) {\n        const auto& c = cand[ord[k]];\n        best = min(best, len + 1 + lookahead_cost(c.st, depth - 1, mode));\n    }\n    return best;\n}\n\nResult greedy_complete(State st, int mode, int depth, int incumbentEnergy = INF) {\n    Result res;\n    res.energy = 0;\n    pop_all(st, &res.ops);\n\n    while (st.cur <= N) {\n        if (incumbentEnergy < INF) {\n            Features curF = calc_features(st);\n            if (res.energy + curF.solo >= incumbentEnergy) {\n                res.energy = INF;\n                res.ops.clear();\n                return res;\n            }\n        }\n\n        int cur = st.cur;\n        int s = st.st_of[cur];\n        int p = st.pos[cur];\n\n        if (p + 1 >= (int)st.h[s]) {\n            pop_all(st, &res.ops);\n            continue;\n        }\n\n        int len = (int)st.h[s] - p - 1;\n        int v = st.a[s][p + 1];\n\n        int useDepth = depth;\n        if (elapsed_sec() > g_deadline - 0.03) useDepth = 1;\n\n        int bestDst = -1;\n        int bestVal = INF;\n        int bestCur = -1;\n        int bestH = INF;\n        int bestLB = INF;\n        int bestEmpty = -1;\n        int bestNextBlock = INF;\n        int bestAppSolo = INF;\n        int bestAppBad = INF;\n        int bestBaseMin = -1;\n\n        for (int dst = 0; dst < M; ++dst) {\n            if (dst == s) continue;\n            State nx = st;\n            AppendInfo ai = calc_append_info(st, dst);\n            move_blockers(nx, dst);\n            pop_all(nx, nullptr);\n\n            Features f = calc_features(nx);\n            int hval = estimate_from_features(f, mode);\n            int lb = res.energy + (len + 1) + f.solo;\n            if (lb >= incumbentEnergy) continue;\n\n            int val = (len + 1) + (useDepth > 1 ? lookahead_cost(nx, useDepth - 1, mode) : hval);\n\n            if (val < bestVal ||\n                (val == bestVal && lb < bestLB) ||\n                (val == bestVal && lb == bestLB && ai.solo < bestAppSolo) ||\n                (val == bestVal && lb == bestLB && ai.solo == bestAppSolo && ai.bad < bestAppBad) ||\n                (val == bestVal && lb == bestLB && ai.solo == bestAppSolo && ai.bad == bestAppBad && f.empty > bestEmpty) ||\n                (val == bestVal && lb == bestLB && ai.solo == bestAppSolo && ai.bad == bestAppBad && f.empty == bestEmpty && ai.baseMin > bestBaseMin) ||\n                (val == bestVal && lb == bestLB && ai.solo == bestAppSolo && ai.bad == bestAppBad && f.empty == bestEmpty && ai.baseMin == bestBaseMin && f.nextBlock < bestNextBlock) ||\n                (val == bestVal && lb == bestLB && ai.solo == bestAppSolo && ai.bad == bestAppBad && f.empty == bestEmpty && ai.baseMin == bestBaseMin && f.nextBlock == bestNextBlock && nx.cur > bestCur) ||\n                (val == bestVal && lb == bestLB && ai.solo == bestAppSolo && ai.bad == bestAppBad && f.empty == bestEmpty && ai.baseMin == bestBaseMin && f.nextBlock == bestNextBlock && nx.cur == bestCur && hval < bestH) ||\n                (val == bestVal && lb == bestLB && ai.solo == bestAppSolo && ai.bad == bestAppBad && f.empty == bestEmpty && ai.baseMin == bestBaseMin && f.nextBlock == bestNextBlock && nx.cur == bestCur && hval == bestH && dst < bestDst)) {\n                bestVal = val;\n                bestLB = lb;\n                bestDst = dst;\n                bestCur = nx.cur;\n                bestH = hval;\n                bestEmpty = f.empty;\n                bestNextBlock = f.nextBlock;\n                bestAppSolo = ai.solo;\n                bestAppBad = ai.bad;\n                bestBaseMin = ai.baseMin;\n            }\n        }\n\n        if (bestDst == -1) {\n            res.energy = INF;\n            res.ops.clear();\n            return res;\n        }\n\n        res.ops.push_back({v, bestDst + 1});\n        res.energy += len + 1;\n        move_blockers(st, bestDst);\n        pop_all(st, &res.ops);\n    }\n\n    return res;\n}\n\nvector<uint8_t> collect_destinations(const vector<Node>& nodes, int idx) {\n    vector<uint8_t> rev;\n    while (idx != -1 && nodes[idx].parent != -1) {\n        rev.push_back(nodes[idx].actionTo);\n        idx = nodes[idx].parent;\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nstruct ReplayResult {\n    State st;\n    int energy = 0;\n    vector<pair<int,int>> ops;\n};\n\nReplayResult replay_destinations(const State& rawInit, const vector<uint8_t>& dests) {\n    ReplayResult rr;\n    rr.st = rawInit;\n    rr.energy = 0;\n    rr.ops.clear();\n\n    pop_all(rr.st, &rr.ops);\n\n    for (uint8_t to : dests) {\n        if (rr.st.cur > N) break;\n\n        int cur = rr.st.cur;\n        int s = rr.st.st_of[cur];\n        int p = rr.st.pos[cur];\n\n        if (p + 1 >= (int)rr.st.h[s]) {\n            pop_all(rr.st, &rr.ops);\n            continue;\n        }\n\n        int v = rr.st.a[s][p + 1];\n        int len = (int)rr.st.h[s] - p - 1;\n\n        rr.ops.push_back({v, (int)to});\n        rr.energy += len + 1;\n        move_blockers(rr.st, (int)to - 1);\n        pop_all(rr.st, &rr.ops);\n    }\n    return rr;\n}\n\nbool validate_result(const State& rawInit, const Result& res) {\n    if (res.energy >= INF) return false;\n\n    State st = rawInit;\n    int energy = 0;\n\n    for (auto [v, to] : res.ops) {\n        if (to == 0) {\n            if (st.cur != v) return false;\n            if (v < 1 || v > N) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            if ((int)st.pos[v] + 1 != (int)st.h[s]) return false;\n            --st.h[s];\n            st.st_of[v] = REMOVED;\n            ++st.cur;\n        } else {\n            if (v < 1 || v > N || to < 1 || to > M) return false;\n            uint8_t s = st.st_of[v];\n            if (s == REMOVED) return false;\n            int p = st.pos[v];\n            int dst = to - 1;\n            int len = (int)st.h[s] - p;\n            for (int i = p; i < (int)st.h[s]; ++i) {\n                uint8_t x = st.a[s][i];\n                st.a[dst][st.h[dst]] = x;\n                st.st_of[x] = (uint8_t)dst;\n                st.pos[x] = st.h[dst];\n                ++st.h[dst];\n            }\n            st.h[s] = (uint8_t)p;\n            energy += len + 1;\n        }\n    }\n\n    return st.cur == N + 1 && energy == res.energy && (int)res.ops.size() <= 5000;\n}\n\nResult run_beam(const State& rawInit, const Config& cfg, double deadline, int incumbentEnergy) {\n    State start = rawInit;\n    pop_all(start, nullptr);\n\n    vector<Node> nodes;\n    nodes.reserve(cfg.width * 260 + 10);\n    nodes.push_back(Node{start, 0, -1, 0});\n\n    if (start.cur > N) {\n        ReplayResult rr = replay_destinations(rawInit, {});\n        return Result{rr.energy, rr.ops};\n    }\n\n    vector<int> beam = {0};\n    int bestFinishedIdx = -1;\n    int bestFinishedCost = incumbentEnergy;\n\n    while (!beam.empty()) {\n        if (elapsed_sec() > deadline) break;\n\n        vector<TempChild> cand;\n        cand.reserve((int)beam.size() * (M - 1));\n\n        bool hasBestTemp = false;\n        TempChild bestTemp{};\n\n        for (int idx : beam) {\n            const Node& nd = nodes[idx];\n            const State& st = nd.st;\n\n            if (st.cur > N) {\n                if (nd.g < bestFinishedCost) {\n                    bestFinishedCost = nd.g;\n                    bestFinishedIdx = idx;\n                }\n                continue;\n            }\n\n            int cur = st.cur;\n            int s = st.st_of[cur];\n            int p = st.pos[cur];\n\n            if (p + 1 >= (int)st.h[s]) continue;\n\n            int len = (int)st.h[s] - p - 1;\n\n            for (int dst = 0; dst < M; ++dst) {\n                if (dst == s) continue;\n\n                TempChild tc;\n                tc.st = st;\n                AppendInfo ai = calc_append_info(st, dst);\n                move_blockers(tc.st, dst);\n                pop_all(tc.st, nullptr);\n                tc.g = nd.g + len + 1;\n\n                Features f = calc_features(tc.st);\n                tc.lb = tc.g + f.solo;\n                if (tc.lb >= bestFinishedCost) continue; // safe pruning by lower bound\n\n                tc.hval = estimate_from_features(f, cfg.mode);\n                tc.eval = tc.g + tc.hval;\n                tc.empty = f.empty;\n                tc.nextBlock = f.nextBlock;\n                tc.appSolo = ai.solo;\n                tc.appBad = ai.bad;\n                tc.baseMin = ai.baseMin;\n                tc.parent = idx;\n                tc.actionTo = (uint8_t)(dst + 1);\n                tc.cur = tc.st.cur;\n\n                if (tc.st.cur > N) {\n                    if (tc.g < bestFinishedCost &&\n                        (!hasBestTemp || tc.g < bestTemp.g)) {\n                        hasBestTemp = true;\n                        bestTemp = tc;\n                    }\n                } else {\n                    cand.push_back(std::move(tc));\n                }\n            }\n        }\n\n        if (hasBestTemp) {\n            nodes.push_back(Node{bestTemp.st, bestTemp.g, bestTemp.parent, bestTemp.actionTo});\n            bestFinishedIdx = (int)nodes.size() - 1;\n            bestFinishedCost = bestTemp.g;\n        }\n\n        if (cand.empty()) break;\n\n        vector<int> ord(cand.size());\n        iota(ord.begin(), ord.end(), 0);\n        auto cmp = [&](int i, int j) {\n            const auto& A = cand[i];\n            const auto& B = cand[j];\n            if (A.eval != B.eval) return A.eval < B.eval;\n            if (A.hval != B.hval) return A.hval < B.hval;\n            if (A.appSolo != B.appSolo) return A.appSolo < B.appSolo;\n            if (A.appBad != B.appBad) return A.appBad < B.appBad;\n            if (A.empty != B.empty) return A.empty > B.empty;\n            if (A.baseMin != B.baseMin) return A.baseMin > B.baseMin;\n            if (A.nextBlock != B.nextBlock) return A.nextBlock < B.nextBlock;\n            if (A.cur != B.cur) return A.cur > B.cur;\n            if (A.g != B.g) return A.g < B.g;\n            return A.actionTo < B.actionTo;\n        };\n\n        if ((int)ord.size() > cfg.width) {\n            nth_element(ord.begin(), ord.begin() + cfg.width, ord.end(), cmp);\n            ord.resize(cfg.width);\n        }\n        sort(ord.begin(), ord.end(), cmp);\n\n        vector<int> nextBeam;\n        nextBeam.reserve(ord.size());\n        for (int id : ord) {\n            const auto& tc = cand[id];\n            nodes.push_back(Node{tc.st, tc.g, tc.parent, tc.actionTo});\n            nextBeam.push_back((int)nodes.size() - 1);\n        }\n        beam.swap(nextBeam);\n    }\n\n    Result best;\n    best.energy = INF;\n\n    if (bestFinishedIdx != -1) {\n        auto dests = collect_destinations(nodes, bestFinishedIdx);\n        ReplayResult rr = replay_destinations(rawInit, dests);\n        if (rr.st.cur == N + 1) {\n            best.energy = rr.energy;\n            best.ops = std::move(rr.ops);\n        }\n    }\n\n    int tailLimit = 3;\n    if (elapsed_sec() < deadline - 0.08) tailLimit = 4;\n    if (elapsed_sec() < deadline - 0.18) tailLimit = 5;\n\n    for (int t = 0; t < (int)beam.size() && t < tailLimit && elapsed_sec() <= deadline + 0.01; ++t) {\n        int idx = beam[t];\n        auto dests = collect_destinations(nodes, idx);\n        ReplayResult pref = replay_destinations(rawInit, dests);\n\n        Features f = calc_features(pref.st);\n        if (pref.energy + f.solo >= best.energy) continue;\n        if (pref.energy + f.solo >= incumbentEnergy) continue;\n\n        int tailInc = min(best.energy, incumbentEnergy);\n        if (tailInc < INF) {\n            tailInc -= pref.energy;\n            if (tailInc < 0) tailInc = 0;\n        }\n\n        Result tail = greedy_complete(pref.st, cfg.mode, cfg.greedyDepth, tailInc);\n        if (tail.energy >= INF) continue;\n\n        Result candRes;\n        candRes.energy = pref.energy + tail.energy;\n        candRes.ops = std::move(pref.ops);\n        candRes.ops.insert(candRes.ops.end(), tail.ops.begin(), tail.ops.end());\n\n        if (candRes.energy < best.energy ||\n            (candRes.energy == best.energy && candRes.ops.size() < best.ops.size())) {\n            best = std::move(candRes);\n        }\n    }\n\n    if (best.energy == INF) {\n        ReplayResult pref = replay_destinations(rawInit, {});\n        Result tail = greedy_complete(pref.st, cfg.mode, max(1, cfg.greedyDepth), incumbentEnergy);\n        if (tail.energy < INF) {\n            best.energy = pref.energy + tail.energy;\n            best.ops = std::move(pref.ops);\n            best.ops.insert(best.ops.end(), tail.ops.begin(), tail.ops.end());\n        }\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    cin >> N >> M;\n\n    State rawInit{};\n    rawInit.cur = 1;\n    for (int i = 0; i < M; ++i) {\n        rawInit.h[i] = N / M;\n        for (int j = 0; j < N / M; ++j) {\n            int x;\n            cin >> x;\n            rawInit.a[i][j] = (uint8_t)x;\n            rawInit.st_of[x] = (uint8_t)i;\n            rawInit.pos[x] = (uint8_t)j;\n        }\n    }\n\n    Result best;\n    best.energy = INF;\n\n    auto try_update = [&](Result&& cand) {\n        if (!validate_result(rawInit, cand)) return;\n        if (cand.energy < best.energy ||\n            (cand.energy == best.energy && cand.ops.size() < best.ops.size())) {\n            best = std::move(cand);\n        }\n    };\n\n    vector<Config> beamConfigs = {\n        {180, 0, 2},\n        {120, 1, 2},\n        {80,  3, 1},\n        {60,  2, 2},\n    };\n\n    for (const auto& cfg : beamConfigs) {\n        if (elapsed_sec() > g_deadline) break;\n        try_update(run_beam(rawInit, cfg, g_deadline, best.energy));\n    }\n\n    if (elapsed_sec() < g_deadline - 0.10) {\n        Config extra{36, 4, 1};\n        try_update(run_beam(rawInit, extra, g_deadline, best.energy));\n    }\n\n    if (elapsed_sec() < g_deadline) try_update(greedy_complete(rawInit, 0, 2, best.energy));\n    if (elapsed_sec() < g_deadline) try_update(greedy_complete(rawInit, 1, 2, best.energy));\n    if (elapsed_sec() < g_deadline) try_update(greedy_complete(rawInit, 2, 2, best.energy));\n    if (elapsed_sec() < g_deadline) try_update(greedy_complete(rawInit, 3, 1, best.energy));\n    if (elapsed_sec() < g_deadline) try_update(greedy_complete(rawInit, 4, 1, best.energy));\n\n    if (elapsed_sec() < g_deadline - 0.12) {\n        try_update(greedy_complete(rawInit, 0, 3, best.energy));\n    }\n    if (elapsed_sec() < g_deadline - 0.08) {\n        try_update(greedy_complete(rawInit, 4, 2, best.energy));\n    }\n\n    if (best.energy == INF) {\n        Result cur = greedy_complete(rawInit, 0, 2);\n        if (!validate_result(rawInit, cur)) {\n            cur = greedy_complete(rawInit, 1, 1);\n        }\n        best = std::move(cur);\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr long long INF64 = (1LL << 62);\nstatic constexpr int MAXV = 1600;\n\nstruct XorShift64 {\n    uint64_t x;\n    XorShift64(uint64_t seed = chrono::steady_clock::now().time_since_epoch().count()) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int next_int(int n) { return (int)(next() % (uint64_t)n); }\n};\n\nstruct Score {\n    long long num;\n    int L;\n};\n\nstatic inline bool better_score(const Score& a, const Score& b) {\n    __int128 lhs = (__int128)a.num * b.L;\n    __int128 rhs = (__int128)b.num * a.L;\n    if (lhs != rhs) return lhs < rhs;\n    return a.L < b.L;\n}\n\nstruct State {\n    vector<int> parent;\n    vector<int> sz, depth, tin, tout;\n    vector<long long> subD;\n    long long num = INF64;\n};\n\nstruct Comp {\n    string route;\n    vector<int> pos; // pos[0]=0\n    int len = 0;\n    Score score{INF64, 1};\n    long long hint = 0;\n};\n\nint N, Vn, TREE_LEN;\nvector<int> g[MAXV];\nint dirtv[MAXV];\nlong long sqrtv_[MAXV];\nlong long imp1[MAXV], imp2[MAXV], imp3[MAXV], imp4[MAXV];\nint distRoot[MAXV], bfsParent[MAXV];\nlong long pathHotD[MAXV], pathHotS[MAXV];\nvector<int> bfsOrder;\n\nint firstOcc[MAXV], lastOcc[MAXV];\nlong long gapAcc[MAXV];\n\nXorShift64 rng;\nchrono::steady_clock::time_point global_start_time;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - global_start_time).count();\n}\n\ninline int vid(int r, int c) { return r * N + c; }\n\ninline char move_char(int a, int b) {\n    if (b == a + 1) return 'R';\n    if (b == a - 1) return 'L';\n    if (b == a + N) return 'D';\n    return 'U';\n}\n\ninline long long tri(long long x) {\n    return x * (x - 1) / 2;\n}\n\ninline long long node_term(int x, int szx, int parentD) {\n    long long outside_gap = TREE_LEN - 2LL * (szx - 1);\n    long long child_gap = 2LL * szx;\n    return 1LL * dirtv[x] * tri(outside_gap) + 1LL * parentD * tri(child_gap);\n}\n\nuint64_t hash_route(const string& s) {\n    uint64_t h = 1469598103934665603ULL;\n    for (unsigned char c : s) {\n        h ^= (uint64_t)c;\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)s.size() + 0x9e3779b97f4a7c15ULL;\n    h *= 1099511628211ULL;\n    return h;\n}\n\nvoid compute_root_bfs() {\n    fill(distRoot, distRoot + Vn, -1);\n    fill(bfsParent, bfsParent + Vn, -1);\n    bfsOrder.clear();\n    queue<int> q;\n    distRoot[0] = 0;\n    q.push(0);\n    bfsOrder.push_back(0);\n    while (!q.empty()) {\n        int u = q.front();\n        q.pop();\n        for (int to : g[u]) {\n            if (distRoot[to] == -1) {\n                distRoot[to] = distRoot[u] + 1;\n                bfsParent[to] = u;\n                q.push(to);\n                bfsOrder.push_back(to);\n            }\n        }\n    }\n}\n\nState build_state(const vector<int>& parent) {\n    State st;\n    st.parent = parent;\n    st.sz.assign(Vn, 1);\n    st.depth.assign(Vn, 0);\n    st.tin.assign(Vn, 0);\n    st.tout.assign(Vn, 0);\n    st.subD.assign(Vn, 0);\n\n    static vector<int> ch[MAXV];\n    for (int i = 0; i < Vn; i++) ch[i].clear();\n    for (int v = 1; v < Vn; v++) ch[parent[v]].push_back(v);\n\n    vector<int> post;\n    post.reserve(Vn);\n    int timer = 0;\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        st.tin[u] = timer++;\n        for (int c : ch[u]) {\n            st.depth[c] = st.depth[u] + 1;\n            self(self, c);\n        }\n        st.tout[u] = timer;\n        post.push_back(u);\n    };\n    dfs(dfs, 0);\n\n    for (int u : post) {\n        st.sz[u] = 1;\n        st.subD[u] = dirtv[u];\n        for (int c : ch[u]) {\n            st.sz[u] += st.sz[c];\n            st.subD[u] += st.subD[c];\n        }\n    }\n\n    long long num = 0;\n    for (int x = 1; x < Vn; x++) {\n        num += node_term(x, st.sz[x], dirtv[st.parent[x]]);\n    }\n    st.num = num;\n    return st;\n}\n\ninline bool is_descendant(const State& st, int x, int anc) {\n    return st.tin[anc] <= st.tin[x] && st.tout[x] <= st.tout[anc];\n}\n\nint lca_slow(const State& st, int a, int b) {\n    while (st.depth[a] > st.depth[b]) a = st.parent[a];\n    while (st.depth[b] > st.depth[a]) b = st.parent[b];\n    while (a != b) {\n        a = st.parent[a];\n        b = st.parent[b];\n    }\n    return a;\n}\n\nlong long delta_reparent(const State& st, int u, int w) {\n    int p = st.parent[u];\n    int s = st.sz[u];\n    int l = lca_slow(st, p, w);\n\n    long long delta = 0;\n    delta += node_term(u, s, dirtv[w]) - node_term(u, s, dirtv[p]);\n\n    for (int x = p; x != l; x = st.parent[x]) {\n        delta += node_term(x, st.sz[x] - s, dirtv[st.parent[x]])\n               - node_term(x, st.sz[x],     dirtv[st.parent[x]]);\n    }\n    for (int x = w; x != l; x = st.parent[x]) {\n        delta += node_term(x, st.sz[x] + s, dirtv[st.parent[x]])\n               - node_term(x, st.sz[x],     dirtv[st.parent[x]]);\n    }\n\n    return delta;\n}\n\nlong long rand_noise(long long amp) {\n    if (amp == 0) return 0;\n    return (long long)(rng.next() % (uint64_t)(2 * amp + 1)) - amp;\n}\n\nvector<int> gen_spt(const long long* imp) {\n    vector<int> parent(Vn, -1);\n    for (int u = 1; u < Vn; u++) {\n        int best = -1;\n        for (int p : g[u]) {\n            if (distRoot[p] == distRoot[u] - 1) {\n                if (best == -1 || imp[p] > imp[best] || (imp[p] == imp[best] && p < best)) best = p;\n            }\n        }\n        parent[u] = best;\n    }\n    return parent;\n}\n\nvector<int> gen_weighted_dfs(const long long* imp, long long noise) {\n    vector<int> parent(Vn, -1);\n    vector<char> vis(Vn, 0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        vis[u] = 1;\n        vector<pair<long long, int>> cand;\n        cand.reserve(g[u].size());\n        for (int to : g[u]) cand.push_back({imp[to] + rand_noise(noise), to});\n        sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        for (auto& e : cand) {\n            int to = e.second;\n            if (!vis[to]) {\n                parent[to] = u;\n                self(self, to);\n            }\n        }\n    };\n    dfs(dfs, 0);\n    return parent;\n}\n\nvector<int> gen_prim(const long long* imp, long long noise, int depthPenalty) {\n    struct Node {\n        long long key;\n        uint64_t tie;\n        int from, to;\n        bool operator<(const Node& other) const {\n            if (key != other.key) return key < other.key;\n            return tie < other.tie;\n        }\n    };\n\n    vector<int> parent(Vn, -1), depth(Vn, 0);\n    vector<char> used(Vn, 0);\n    priority_queue<Node> pq;\n\n    auto push_edges = [&](int u) {\n        for (int to : g[u]) if (!used[to]) {\n            long long key = imp[to] - 1LL * depthPenalty * depth[u] + rand_noise(noise);\n            pq.push({key, rng.next(), u, to});\n        }\n    };\n\n    used[0] = 1;\n    int cnt = 1;\n    push_edges(0);\n\n    while (!pq.empty() && cnt < Vn) {\n        auto cur = pq.top();\n        pq.pop();\n        if (used[cur.to]) continue;\n        used[cur.to] = 1;\n        parent[cur.to] = cur.from;\n        depth[cur.to] = depth[cur.from] + 1;\n        cnt++;\n        push_edges(cur.to);\n    }\n\n    if (cnt < Vn) return gen_weighted_dfs(imp, 0);\n    return parent;\n}\n\nvector<int> make_static_hot_list() {\n    vector<pair<long long, int>> cand;\n    cand.reserve(4 * Vn);\n    for (int u = 1; u < Vn; u++) {\n        cand.push_back({1LL * dirtv[u] * 1000000LL, u});\n        cand.push_back({sqrtv_[u] * 1000000LL, u});\n        cand.push_back({1LL * dirtv[u] * 1000000LL / (distRoot[u] + 1), u});\n        cand.push_back({sqrtv_[u] * 1000000LL / (distRoot[u] + 1), u});\n    }\n    sort(cand.begin(), cand.end(), [&](auto& A, auto& B) {\n        if (A.first != B.first) return A.first > B.first;\n        return A.second < B.second;\n    });\n    vector<int> res;\n    vector<char> used(Vn, 0);\n    for (auto& e : cand) {\n        int u = e.second;\n        if (!used[u]) {\n            used[u] = 1;\n            res.push_back(u);\n            if ((int)res.size() >= 220) break;\n        }\n    }\n    return res;\n}\n\nvector<int> make_top_bad(const State& st, int limit = 120) {\n    vector<pair<long long, int>> vec;\n    vec.reserve(Vn - 1);\n    for (int x = 1; x < Vn; x++) {\n        vec.push_back({node_term(x, st.sz[x], dirtv[st.parent[x]]), x});\n    }\n    sort(vec.begin(), vec.end(), [&](auto& A, auto& B) {\n        if (A.first != B.first) return A.first > B.first;\n        return A.second < B.second;\n    });\n    vector<int> res;\n    for (int i = 0; i < (int)vec.size() && i < limit; i++) res.push_back(vec[i].second);\n    return res;\n}\n\nvoid consider_pool(vector<State>& pool, const State& st, int maxPool = 6) {\n    if ((int)pool.size() >= maxPool && st.num >= pool.back().num) return;\n    pool.push_back(st);\n    sort(pool.begin(), pool.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n    if ((int)pool.size() > maxPool) pool.pop_back();\n}\n\nvoid build_children_sorted(const State& st, vector<vector<int>>& ch, int mode) {\n    ch.assign(Vn, {});\n    for (int v = 1; v < Vn; v++) ch[st.parent[v]].push_back(v);\n\n    for (int u = 0; u < Vn; u++) {\n        if (mode == 0) {\n            sort(ch[u].begin(), ch[u].end(), [&](int a, int b) {\n                if (st.subD[a] != st.subD[b]) return st.subD[a] > st.subD[b];\n                return a < b;\n            });\n        } else if (mode == 1) {\n            sort(ch[u].begin(), ch[u].end(), [&](int a, int b) {\n                __int128 lhs = (__int128)st.subD[a] * st.sz[b];\n                __int128 rhs = (__int128)st.subD[b] * st.sz[a];\n                if (lhs != rhs) return lhs > rhs;\n                if (st.subD[a] != st.subD[b]) return st.subD[a] > st.subD[b];\n                return a < b;\n            });\n        } else {\n            sort(ch[u].begin(), ch[u].end(), [&](int a, int b) {\n                long long ka = 1024LL * dirtv[a] + st.subD[a] / max(1, st.sz[a]);\n                long long kb = 1024LL * dirtv[b] + st.subD[b] / max(1, st.sz[b]);\n                if (ka != kb) return ka > kb;\n                if (st.subD[a] != st.subD[b]) return st.subD[a] > st.subD[b];\n                return a < b;\n            });\n        }\n    }\n}\n\nComp build_global_route(const State& st, int orderMode) {\n    vector<vector<int>> ch;\n    build_children_sorted(st, ch, orderMode);\n\n    Comp C;\n    C.route.reserve(TREE_LEN);\n    C.pos.reserve(TREE_LEN + 1);\n    C.pos.push_back(0);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        for (int c : ch[u]) {\n            C.route.push_back(move_char(u, c));\n            C.pos.push_back(c);\n            self(self, c);\n            C.route.push_back(move_char(c, u));\n            C.pos.push_back(u);\n        }\n    };\n    dfs(dfs, 0);\n\n    C.len = (int)C.route.size();\n    C.score = {st.num, TREE_LEN};\n    return C;\n}\n\nComp build_path_loop(int target) {\n    vector<int> fwd;\n    for (int x = target; x != 0; x = bfsParent[x]) fwd.push_back(x);\n    reverse(fwd.begin(), fwd.end());\n\n    Comp C;\n    C.pos.reserve(2 * (int)fwd.size() + 1);\n    C.pos.push_back(0);\n    for (int v : fwd) C.pos.push_back(v);\n    for (int i = (int)fwd.size() - 2; i >= 0; i--) C.pos.push_back(fwd[i]);\n    C.pos.push_back(0);\n\n    C.route.reserve((int)C.pos.size() - 1);\n    for (int i = 1; i < (int)C.pos.size(); i++) C.route.push_back(move_char(C.pos[i - 1], C.pos[i]));\n    C.len = (int)C.route.size();\n    return C;\n}\n\nComp build_subtree_loop(const State& st, int rootSub, int orderMode) {\n    vector<vector<int>> ch;\n    build_children_sorted(st, ch, orderMode);\n\n    vector<int> path;\n    for (int x = rootSub; x != 0; x = st.parent[x]) path.push_back(x);\n    reverse(path.begin(), path.end());\n\n    Comp C;\n    C.pos.reserve(2 * (st.depth[rootSub] + st.sz[rootSub] - 1) + 3);\n    C.pos.push_back(0);\n    for (int v : path) C.pos.push_back(v);\n\n    auto dfs = [&](auto&& self, int u) -> void {\n        for (int c : ch[u]) {\n            C.pos.push_back(c);\n            self(self, c);\n            C.pos.push_back(u);\n        }\n    };\n    dfs(dfs, rootSub);\n\n    for (int i = (int)path.size() - 2; i >= 0; i--) C.pos.push_back(path[i]);\n    C.pos.push_back(0);\n\n    C.route.reserve((int)C.pos.size() - 1);\n    for (int i = 1; i < (int)C.pos.size(); i++) C.route.push_back(move_char(C.pos[i - 1], C.pos[i]));\n    C.len = (int)C.route.size();\n    return C;\n}\n\nScore evaluate_positions(const vector<int>& pos) {\n    int L = (int)pos.size() - 1;\n    fill(firstOcc, firstOcc + Vn, -1);\n    fill(gapAcc, gapAcc + Vn, 0LL);\n\n    long long num = 0;\n    for (int t = 1; t <= L; t++) {\n        int x = pos[t];\n        if (firstOcc[x] == -1) {\n            firstOcc[x] = t;\n        } else {\n            long long g = t - lastOcc[x];\n            gapAcc[x] += g * (g - 1) / 2;\n        }\n        lastOcc[x] = t;\n    }\n    for (int x = 0; x < Vn; x++) {\n        if (firstOcc[x] == -1) return {INF64, L};\n        long long g = firstOcc[x] + L - lastOcc[x];\n        gapAcc[x] += g * (g - 1) / 2;\n        num += gapAcc[x] * 1LL * dirtv[x];\n    }\n    return {num, L};\n}\n\nScore evaluate_combo1(const Comp& H, int k, const Comp& B) {\n    static vector<int> pos;\n    pos.clear();\n    pos.reserve(1 + k * H.len + B.len);\n    pos.push_back(0);\n    for (int rep = 0; rep < k; rep++) pos.insert(pos.end(), H.pos.begin() + 1, H.pos.end());\n    pos.insert(pos.end(), B.pos.begin() + 1, B.pos.end());\n    return evaluate_positions(pos);\n}\n\nvector<int> make_k_list(int limit) {\n    vector<int> ks;\n    ks.push_back(0);\n    for (int k = 1; k <= min(limit, 10); k++) ks.push_back(k);\n    for (int k = 16; k <= limit; ) {\n        ks.push_back(k);\n        int nk = k + max(2, k / 2);\n        if (nk == k) nk++;\n        k = nk;\n    }\n    if (limit > 0) ks.push_back(limit);\n    sort(ks.begin(), ks.end());\n    ks.erase(unique(ks.begin(), ks.end()), ks.end());\n    return ks;\n}\n\nvoid add_refine(vector<int>& ks, int limit, int center) {\n    int L = max(0, center - 8);\n    int R = min(limit, center + 8);\n    for (int k = L; k <= R; k++) ks.push_back(k);\n    sort(ks.begin(), ks.end());\n    ks.erase(unique(ks.begin(), ks.end()), ks.end());\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N;\n    vector<string> h(N - 1), vwall(N);\n    for (int i = 0; i < N - 1; i++) cin >> h[i];\n    for (int i = 0; i < N; i++) cin >> vwall[i];\n\n    Vn = N * N;\n    TREE_LEN = 2 * (Vn - 1);\n    for (int i = 0; i < Vn; i++) g[i].clear();\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> dirtv[vid(i, j)];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int a = vid(i, j);\n            if (i + 1 < N && h[i][j] == '0') {\n                int b = vid(i + 1, j);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int b = vid(i, j + 1);\n                g[a].push_back(b);\n                g[b].push_back(a);\n            }\n        }\n    }\n\n    for (int u = 0; u < Vn; u++) sqrtv_[u] = llround(1000.0 * sqrt((double)dirtv[u]));\n    for (int u = 0; u < Vn; u++) {\n        long long s1 = 0, s2 = 0;\n        for (int to : g[u]) {\n            s1 += dirtv[to];\n            s2 += sqrtv_[to];\n        }\n        imp1[u] = dirtv[u];\n        imp2[u] = sqrtv_[u];\n        imp3[u] = 100LL * dirtv[u] + 35LL * s1;\n        imp4[u] = 100LL * sqrtv_[u] + 35LL * s2;\n    }\n\n    compute_root_bfs();\n    pathHotD[0] = 0;\n    pathHotS[0] = 0;\n    for (int i = 1; i < (int)bfsOrder.size(); i++) {\n        int u = bfsOrder[i];\n        int p = bfsParent[u];\n        pathHotD[u] = pathHotD[p] + dirtv[u];\n        pathHotS[u] = pathHotS[p] + sqrtv_[u];\n    }\n\n    global_start_time = chrono::steady_clock::now();\n\n    const double DESCENT_END = 0.96;\n    const double SEARCH_END  = 1.34;\n    const double POLISH_END  = 1.58;\n    const double FINAL_END   = 1.80;\n\n    vector<const long long*> imps = {imp1, imp2, imp3, imp4};\n    vector<int> staticHot = make_static_hot_list();\n\n    vector<State> initStates;\n    initStates.reserve(80);\n\n    auto add_init_parent = [&](const vector<int>& parent) {\n        initStates.push_back(build_state(parent));\n    };\n\n    add_init_parent(gen_spt(imp1));\n    add_init_parent(gen_spt(imp2));\n    add_init_parent(gen_spt(imp3));\n    add_init_parent(gen_spt(imp4));\n\n    for (const long long* imp : imps) {\n        for (long long nz : {0LL, 4000LL, 15000LL, 50000LL}) {\n            int reps = (nz == 0 ? 1 : 2);\n            for (int rep = 0; rep < reps; rep++) add_init_parent(gen_weighted_dfs(imp, nz));\n        }\n        for (long long nz : {0LL, 6000LL, 20000LL}) {\n            for (int pen : {0, 120, 300}) add_init_parent(gen_prim(imp, nz, pen));\n        }\n    }\n\n    sort(initStates.begin(), initStates.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n\n    vector<State> pool;\n    State best = initStates[0];\n    consider_pool(pool, best);\n\n    auto steepest_descent = [&](State st, double time_limit, int step_limit) -> State {\n        int steps = 0;\n        while (elapsed_sec() < time_limit && steps < step_limit) {\n            long long bestDelta = 0;\n            int bestu = -1, bestw = -1;\n            long long bestTie = LLONG_MIN;\n\n            for (int u = 1; u < Vn; u++) {\n                int pu = st.parent[u];\n                for (int w : g[u]) {\n                    if (w == pu) continue;\n                    if (is_descendant(st, w, u)) continue;\n\n                    long long delta = delta_reparent(st, u, w);\n                    long long tie = 1LL * (dirtv[w] - dirtv[pu]) * 1000 - st.depth[w];\n\n                    if (delta < bestDelta || (delta == bestDelta && tie > bestTie)) {\n                        bestDelta = delta;\n                        bestTie = tie;\n                        bestu = u;\n                        bestw = w;\n                    }\n                }\n            }\n\n            if (bestu == -1) break;\n            st.parent[bestu] = bestw;\n            st = build_state(st.parent);\n            steps++;\n        }\n        return st;\n    };\n\n    auto targeted_polish = [&](State st, double time_limit, int step_limit) -> State {\n        int steps = 0;\n        while (elapsed_sec() < time_limit && steps < step_limit) {\n            vector<int> bad = make_top_bad(st, 80);\n            vector<int> candU;\n            candU.reserve(140);\n            vector<char> used(Vn, 0);\n\n            for (int u : bad) {\n                if (!used[u]) {\n                    used[u] = 1;\n                    candU.push_back(u);\n                }\n            }\n            for (int i = 0; i < (int)staticHot.size() && i < 40; i++) {\n                int u = staticHot[i];\n                if (!used[u]) {\n                    used[u] = 1;\n                    candU.push_back(u);\n                }\n            }\n\n            long long bestDelta = 0;\n            int bestu = -1, bestw = -1;\n            long long bestTie = LLONG_MIN;\n\n            for (int u : candU) {\n                int pu = st.parent[u];\n                for (int w : g[u]) {\n                    if (w == pu) continue;\n                    if (is_descendant(st, w, u)) continue;\n\n                    long long delta = delta_reparent(st, u, w);\n                    long long tie = 1LL * (dirtv[w] - dirtv[pu]) * 1000 - st.depth[w];\n\n                    if (delta < bestDelta || (delta == bestDelta && tie > bestTie)) {\n                        bestDelta = delta;\n                        bestTie = tie;\n                        bestu = u;\n                        bestw = w;\n                    }\n                }\n            }\n\n            if (bestu == -1) break;\n            st.parent[bestu] = bestw;\n            st = build_state(st.parent);\n            steps++;\n        }\n        return st;\n    };\n\n    auto perturb_state = [&](const State& base) -> State {\n        State st = base;\n        int kicks = 1 + rng.next_int(2);\n\n        for (int rep = 0; rep < kicks; rep++) {\n            vector<int> topBad = make_top_bad(st, 60);\n            vector<char> usedU(Vn, 0);\n\n            struct MoveCand {\n                long long delta;\n                int u, w;\n                long long key;\n            };\n            vector<MoveCand> cands;\n            cands.reserve(256);\n\n            auto add_u = [&](int u) {\n                if (u <= 0 || u >= Vn || usedU[u]) return;\n                usedU[u] = 1;\n                int pu = st.parent[u];\n                for (int w : g[u]) {\n                    if (w == pu) continue;\n                    if (is_descendant(st, w, u)) continue;\n                    long long delta = delta_reparent(st, u, w);\n                    long long key = 1LL * (dirtv[w] - dirtv[pu]) * 1000 - st.depth[w];\n                    cands.push_back({delta, u, w, key});\n                }\n            };\n\n            for (int i = 0; i < (int)topBad.size() && i < 30; i++) add_u(topBad[i]);\n            for (int i = 0; i < (int)staticHot.size() && i < 20; i++) add_u(staticHot[i]);\n            for (int i = 0; i < 16; i++) add_u(1 + rng.next_int(Vn - 1));\n\n            if (cands.empty()) break;\n\n            sort(cands.begin(), cands.end(), [&](const MoveCand& A, const MoveCand& B) {\n                if (A.delta != B.delta) return A.delta < B.delta;\n                return A.key > B.key;\n            });\n\n            int pickLim;\n            if (rng.next_int(100) < 70) pickLim = min(6, (int)cands.size());\n            else pickLim = min(20, (int)cands.size());\n\n            int idx = rng.next_int(pickLim);\n            st.parent[cands[idx].u] = cands[idx].w;\n            st = build_state(st.parent);\n        }\n        return st;\n    };\n\n    int seedCount = min((int)initStates.size(), 8);\n    for (int i = 0; i < seedCount && elapsed_sec() < DESCENT_END; i++) {\n        State st = steepest_descent(initStates[i], DESCENT_END, 60);\n        consider_pool(pool, st);\n        if (st.num < best.num) best = st;\n    }\n\n    while (elapsed_sec() < SEARCH_END) {\n        State base;\n        if (!pool.empty() && rng.next_int(100) < 85) {\n            base = pool[rng.next_int(min(3, (int)pool.size()))];\n        } else {\n            const long long* imp = imps[rng.next_int((int)imps.size())];\n            if (rng.next_int(2) == 0) {\n                static const long long noises[] = {0, 4000, 15000, 50000};\n                base = build_state(gen_weighted_dfs(imp, noises[rng.next_int(4)]));\n            } else {\n                static const long long noises[] = {0, 6000, 20000};\n                static const int pens[] = {0, 120, 300};\n                base = build_state(gen_prim(imp, noises[rng.next_int(3)], pens[rng.next_int(3)]));\n            }\n        }\n\n        State pert = perturb_state(base);\n        State st = steepest_descent(pert, SEARCH_END, 36);\n        consider_pool(pool, st);\n        if (st.num < best.num) best = st;\n    }\n\n    sort(pool.begin(), pool.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n\n    for (int i = 0; i < (int)pool.size() && i < 2 && elapsed_sec() < POLISH_END; i++) {\n        State st = targeted_polish(pool[i], POLISH_END, 50);\n        consider_pool(pool, st);\n        if (st.num < best.num) best = st;\n    }\n\n    if (elapsed_sec() < POLISH_END) {\n        best = steepest_descent(best, POLISH_END, 24);\n        consider_pool(pool, best);\n    }\n\n    sort(pool.begin(), pool.end(), [&](const State& a, const State& b) {\n        return a.num < b.num;\n    });\n\n    vector<State> finalStates;\n    for (int i = 0; i < (int)pool.size() && i < 3; i++) finalStates.push_back(pool[i]);\n    if (finalStates.empty()) finalStates.push_back(best);\n\n    vector<Comp> globals;\n    unordered_set<uint64_t> seenGlobal;\n\n    auto add_global = [&](const State& st, int mode) {\n        Comp C = build_global_route(st, mode);\n        uint64_t h = hash_route(C.route);\n        if (seenGlobal.insert(h).second) globals.push_back(move(C));\n    };\n\n    for (const State& st : finalStates) {\n        add_global(st, 0);\n        add_global(st, 1);\n        add_global(st, 2);\n    }\n\n    sort(globals.begin(), globals.end(), [&](const Comp& a, const Comp& b) {\n        return better_score(a.score, b.score);\n    });\n    if ((int)globals.size() > 7) globals.resize(7);\n\n    Score answerScore = globals[0].score;\n    string answerRoute = globals[0].route;\n\n    vector<Comp> loops;\n    unordered_set<uint64_t> seenLoop;\n\n    auto add_loop = [&](Comp&& C, long long hint) {\n        if (C.len <= 0 || C.len >= 100000) return;\n        uint64_t h = hash_route(C.route);\n        if (seenLoop.insert(h).second) {\n            C.hint = hint;\n            loops.push_back(move(C));\n        }\n    };\n\n    int loopStates = min(2, (int)finalStates.size());\n    for (int si = 0; si < loopStates && elapsed_sec() < FINAL_END; si++) {\n        const State& st = finalStates[si];\n\n        vector<pair<long long, int>> cand1;\n        for (int u = 1; u < Vn; u++) {\n            if (distRoot[u] <= 6) {\n                long long len = 2LL * distRoot[u];\n                long long sq = max(1LL, len * len);\n                long long keyA = pathHotD[u] * 1000000LL / sq;\n                long long keyB = 1LL * dirtv[u] * 1000000LL / sq;\n                long long keyC = pathHotS[u] * 30000LL / sq;\n                long long key = max(keyA, max(keyB, keyC));\n                cand1.push_back({key, u});\n            }\n        }\n        sort(cand1.begin(), cand1.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        vector<char> used1(Vn, 0);\n        for (int i = 0, cnt = 0; i < (int)cand1.size() && cnt < 4; i++) {\n            int u = cand1[i].second;\n            if (used1[u]) continue;\n            used1[u] = 1;\n            Comp H = build_path_loop(u);\n            if (H.len <= 16) {\n                add_loop(move(H), cand1[i].first);\n                cnt++;\n            }\n        }\n\n        vector<pair<long long, int>> cand2;\n        for (int u = 1; u < Vn; u++) {\n            int len = 2 * (st.depth[u] + st.sz[u] - 1);\n            if (len <= 40 && st.depth[u] <= 8) {\n                long long key = st.subD[u] * 1000000LL / max(1, len * len);\n                cand2.push_back({key, u});\n            }\n        }\n        sort(cand2.begin(), cand2.end(), [&](auto& A, auto& B) {\n            if (A.first != B.first) return A.first > B.first;\n            return A.second < B.second;\n        });\n        for (int i = 0; i < (int)cand2.size() && i < 4; i++) {\n            add_loop(build_subtree_loop(st, cand2[i].second, 0), cand2[i].first);\n            add_loop(build_subtree_loop(st, cand2[i].second, 1), cand2[i].first);\n        }\n    }\n\n    sort(loops.begin(), loops.end(), [&](const Comp& a, const Comp& b) {\n        if (a.hint != b.hint) return a.hint > b.hint;\n        return a.len < b.len;\n    });\n    if ((int)loops.size() > 8) loops.resize(8);\n\n    int baseTry = min(4, (int)globals.size());\n    int loopTry = min(8, (int)loops.size());\n\n    for (int bi = 0; bi < baseTry && elapsed_sec() < FINAL_END; bi++) {\n        const Comp& B = globals[bi];\n        for (int hi = 0; hi < loopTry && elapsed_sec() < FINAL_END; hi++) {\n            const Comp& H = loops[hi];\n            int limit = (100000 - B.len) / H.len;\n            if (limit <= 0) continue;\n\n            vector<int> ks = make_k_list(limit);\n            int bestK = 0;\n            Score localBest = B.score;\n\n            for (int k : ks) {\n                Score sc = (k == 0 ? B.score : evaluate_combo1(H, k, B));\n                if (better_score(sc, localBest)) {\n                    localBest = sc;\n                    bestK = k;\n                }\n            }\n\n            add_refine(ks, limit, bestK);\n            for (int k : ks) {\n                Score sc = (k == 0 ? B.score : evaluate_combo1(H, k, B));\n                if (better_score(sc, localBest)) {\n                    localBest = sc;\n                    bestK = k;\n                }\n            }\n\n            if (bestK > 0 && better_score(localBest, answerScore)) {\n                answerScore = localBest;\n                string route;\n                route.reserve(bestK * H.len + B.len);\n                for (int rep = 0; rep < bestK; rep++) route += H.route;\n                route += B.route;\n                answerRoute = move(route);\n            }\n        }\n    }\n\n    if (answerRoute.empty() || (int)answerRoute.size() > 100000) {\n        answerRoute = build_global_route(best, 0).route;\n    }\n\n    cout << answerRoute << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"Ofast,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU(int n = 0) { init(n); }\n    void init(int n) {\n        p.resize(n);\n        sz.assign(n, 1);\n        iota(p.begin(), p.end(), 0);\n    }\n    int find(int x) {\n        while (p[x] != x) {\n            p[x] = p[p[x]];\n            x = p[x];\n        }\n        return x;\n    }\n    bool same(int a, int b) { return find(a) == find(b); }\n    bool unite(int a, int b) {\n        a = find(a), b = find(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        p[b] = a;\n        sz[a] += sz[b];\n        return true;\n    }\n};\n\nstruct Solver {\n    static constexpr int PMAX = 225;\n    static constexpr int MMAX = 200;\n    static constexpr int INF = 1e9;\n\n    int N, M;\n    int si, sj, startPos;\n\n    vector<string> board;\n    vector<string> words;\n    vector<array<int, 5>> w;\n\n    array<vector<int>, 26> occ;\n    int man[PMAX][PMAX];\n\n    int ov[MMAX][MMAX];\n    int lastc[MMAX];\n    int endCnt[MMAX];\n\n    struct MatInfo {\n        vector<uint16_t> a; // row-major\n    };\n    vector<MatInfo> mats; // [26][M][5]\n\n    vector<vector<uint16_t>> startVec;\n    int startApprox[MMAX];\n    int edgeApprox[MMAX][MMAX];\n    int bestOutApprox[MMAX];\n\n    int pairExact[MMAX][MMAX];\n    int bestPairFrom[MMAX];\n    vector<tuple<int, int, int>> exactPairList; // (cost, a, b)\n\n    uint32_t baseSeed = 1;\n    mt19937 rng;\n\n    chrono::steady_clock::time_point t0;\n    double TL = 1.88;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - t0).count();\n    }\n    inline bool timeup(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline MatInfo& MAT(int c, int j, int st) {\n        return mats[(c * M + j) * 5 + st];\n    }\n    inline const MatInfo& MAT(int c, int j, int st) const {\n        return mats[(c * M + j) * 5 + st];\n    }\n\n    void readInput() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> N >> M;\n        cin >> si >> sj;\n        startPos = si * N + sj;\n\n        board.resize(N);\n        for (int i = 0; i < N; i++) cin >> board[i];\n\n        words.resize(M);\n        w.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) w[i][k] = words[i][k] - 'A';\n            lastc[i] = w[i][4];\n        }\n    }\n\n    void buildSeed() {\n        uint64_t h = 1469598103934665603ULL;\n        auto mix = [&](uint64_t x) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n        mix(N); mix(M); mix(si); mix(sj);\n        for (auto& row : board) for (char c : row) mix((uint64_t)c);\n        for (auto& s : words) for (char c : s) mix((uint64_t)c);\n        baseSeed = (uint32_t)(h ^ (h >> 32));\n        if (baseSeed == 0) baseSeed = 1;\n        rng.seed(baseSeed);\n    }\n\n    void precomputeKeyboard() {\n        for (auto& v : occ) v.clear();\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int id = i * N + j;\n                occ[board[i][j] - 'A'].push_back(id);\n            }\n        }\n        for (int p = 0; p < N * N; p++) {\n            int pi = p / N, pj = p % N;\n            for (int q = 0; q < N * N; q++) {\n                int qi = q / N, qj = q % N;\n                man[p][q] = abs(pi - qi) + abs(pj - qj);\n            }\n        }\n        for (int i = 0; i < M; i++) endCnt[i] = (int)occ[lastc[i]].size();\n    }\n\n    int calcOverlap(const string& a, const string& b) const {\n        for (int len = 4; len >= 1; len--) {\n            bool ok = true;\n            for (int k = 0; k < len; k++) {\n                if (a[5 - len + k] != b[k]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return len;\n        }\n        return 0;\n    }\n\n    void precomputeOverlaps() {\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                ov[i][j] = (i == j ? 0 : calcOverlap(words[i], words[j]));\n            }\n        }\n    }\n\n    vector<uint16_t> buildMatFromSources(const vector<int>& srcPos, int wid, int st) {\n        int R = (int)srcPos.size();\n        int C = endCnt[wid];\n        vector<uint16_t> res(R * C);\n\n        int prevCost[PMAX], curCost[PMAX];\n\n        for (int r = 0; r < R; r++) {\n            int src = srcPos[r];\n\n            int prevChar = w[wid][st];\n            int pcnt = (int)occ[prevChar].size();\n            const vector<int>& firstPos = occ[prevChar];\n            for (int i = 0; i < pcnt; i++) {\n                prevCost[i] = man[src][firstPos[i]] + 1;\n            }\n\n            for (int k = st + 1; k < 5; k++) {\n                int curChar = w[wid][k];\n                const vector<int>& prevPos = occ[prevChar];\n                const vector<int>& curPos = occ[curChar];\n                int ccnt = (int)curPos.size();\n\n                for (int ci = 0; ci < ccnt; ci++) {\n                    int q = curPos[ci];\n                    int best = INF;\n                    for (int pi = 0; pi < pcnt; pi++) {\n                        int cand = prevCost[pi] + man[prevPos[pi]][q] + 1;\n                        if (cand < best) best = cand;\n                    }\n                    curCost[ci] = best;\n                }\n                for (int i = 0; i < ccnt; i++) prevCost[i] = curCost[i];\n                pcnt = ccnt;\n                prevChar = curChar;\n            }\n\n            for (int e = 0; e < C; e++) {\n                res[r * C + e] = (uint16_t)prevCost[e];\n            }\n        }\n        return res;\n    }\n\n    void precomputeMatrices() {\n        mats.resize(26 * M * 5);\n        startVec.assign(M, {});\n\n        for (int j = 0; j < M; j++) {\n            vector<int> src = {startPos};\n            auto v = buildMatFromSources(src, j, 0);\n            startVec[j].assign(v.begin(), v.end());\n\n            int mn = INF, sum = 0;\n            for (uint16_t x : startVec[j]) {\n                mn = min(mn, (int)x);\n                sum += x;\n            }\n            int avg = sum / max(1, (int)startVec[j].size());\n            startApprox[j] = (mn + avg) / 2;\n        }\n\n        for (int c = 0; c < 26; c++) {\n            for (int j = 0; j < M; j++) {\n                for (int st = 0; st < 5; st++) {\n                    MAT(c, j, st).a = buildMatFromSources(occ[c], j, st);\n                }\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            edgeApprox[i][i] = INF / 4;\n            for (int j = 0; j < M; j++) if (i != j) {\n                int c = lastc[i];\n                int st = ov[i][j];\n                const auto& arr = MAT(c, j, st).a;\n                int rows = (int)occ[c].size();\n                int cols = endCnt[j];\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                const uint16_t* p = arr.data();\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    const uint16_t* row = p + r * cols;\n                    for (int e = 0; e < cols; e++) {\n                        int v = row[e];\n                        if (v < rowMin) rowMin = v;\n                        if (v < globalMin) globalMin = v;\n                    }\n                    sumRowMin += rowMin;\n                }\n                int avgRowMin = (int)(sumRowMin / max(1, rows));\n                edgeApprox[i][j] = (globalMin + avgRowMin) / 2;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            int best = INF;\n            for (int j = 0; j < M; j++) if (i != j) {\n                best = min(best, edgeApprox[i][j]);\n            }\n            bestOutApprox[i] = best;\n        }\n    }\n\n    int exactPairCost(int a, int b) const {\n        if (a == b) return INF / 4;\n        int cols = endCnt[b];\n        int ndp[PMAX];\n        for (int e = 0; e < cols; e++) ndp[e] = INF;\n\n        int c = lastc[a];\n        int st = ov[a][b];\n        const auto& arr = MAT(c, b, st).a;\n        const uint16_t* matp = arr.data();\n        int rows = endCnt[a];\n\n        for (int r = 0; r < rows; r++) {\n            int base = startVec[a][r];\n            const uint16_t* row = matp + r * cols;\n            for (int e = 0; e < cols; e++) {\n                int cand = base + row[e];\n                if (cand < ndp[e]) ndp[e] = cand;\n            }\n        }\n\n        int ans = INF;\n        for (int e = 0; e < cols; e++) ans = min(ans, ndp[e]);\n        return ans;\n    }\n\n    void precomputeExactPairs() {\n        exactPairList.clear();\n        exactPairList.reserve(M * (M - 1));\n        for (int a = 0; a < M; a++) {\n            bestPairFrom[a] = INF;\n            for (int b = 0; b < M; b++) {\n                if (a == b) {\n                    pairExact[a][b] = INF / 4;\n                } else {\n                    int v = exactPairCost(a, b);\n                    pairExact[a][b] = v;\n                    bestPairFrom[a] = min(bestPairFrom[a], v);\n                    exactPairList.emplace_back(v, a, b);\n                }\n            }\n        }\n        sort(exactPairList.begin(), exactPairList.end());\n    }\n\n    int evalPerm(const vector<int>& perm) const {\n        if (perm.empty()) return 0;\n\n        int dp[PMAX], ndp[PMAX];\n        int first = perm[0];\n        int cnt = endCnt[first];\n        for (int e = 0; e < cnt; e++) dp[e] = startVec[first][e];\n\n        for (int idx = 1; idx < (int)perm.size(); idx++) {\n            int a = perm[idx - 1];\n            int b = perm[idx];\n            int c = lastc[a];\n            int st = ov[a][b];\n            const auto& arr = MAT(c, b, st).a;\n            int rows = (int)occ[c].size();\n            int cols = endCnt[b];\n\n            for (int e = 0; e < cols; e++) ndp[e] = INF;\n            const uint16_t* matp = arr.data();\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const uint16_t* row = matp + r * cols;\n                for (int e = 0; e < cols; e++) {\n                    int cand = base + row[e];\n                    if (cand < ndp[e]) ndp[e] = cand;\n                }\n            }\n\n            cnt = cols;\n            for (int e = 0; e < cnt; e++) dp[e] = ndp[e];\n        }\n\n        int ans = INF;\n        for (int e = 0; e < cnt; e++) ans = min(ans, dp[e]);\n        return ans;\n    }\n\n    int transitionCostAndDP(const int* dp, int curWord, int nextWord, int* outDP) const {\n        int c = lastc[curWord];\n        int st = ov[curWord][nextWord];\n        const auto& arr = MAT(c, nextWord, st).a;\n        int rows = (int)occ[c].size();\n        int cols = endCnt[nextWord];\n\n        for (int e = 0; e < cols; e++) outDP[e] = INF;\n        const uint16_t* matp = arr.data();\n\n        for (int r = 0; r < rows; r++) {\n            int base = dp[r];\n            const uint16_t* row = matp + r * cols;\n            for (int e = 0; e < cols; e++) {\n                int cand = base + row[e];\n                if (cand < outDP[e]) outDP[e] = cand;\n            }\n        }\n\n        int best = INF;\n        for (int e = 0; e < cols; e++) best = min(best, outDP[e]);\n        return best;\n    }\n\n    string buildString(const vector<int>& perm) const {\n        string s;\n        if (perm.empty()) return s;\n        s.reserve(5 * (int)perm.size());\n        s += words[perm[0]];\n        for (int i = 1; i < (int)perm.size(); i++) {\n            int o = ov[perm[i - 1]][perm[i]];\n            s.append(words[perm[i]].begin() + o, words[perm[i]].end());\n        }\n        return s;\n    }\n\n    // ---------- Initial constructions ----------\n\n    vector<int> initGreedyAppend(int firstWord, uint32_t seed, bool randomized, int topNext = 4) const {\n        mt19937 rr(seed);\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> used(M, 0);\n\n        int curDP[PMAX], tmpDP[PMAX], chosenDP[PMAX];\n\n        perm.push_back(firstWord);\n        used[firstWord] = 1;\n        int curCnt = endCnt[firstWord];\n        for (int e = 0; e < curCnt; e++) curDP[e] = startVec[firstWord][e];\n        int curWord = firstWord;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                int score2;\n                int scoreExact;\n                int j;\n            };\n            vector<Cand> cand;\n            cand.reserve(M - (int)perm.size());\n\n            int remain = M - (int)perm.size();\n            for (int j = 0; j < M; j++) if (!used[j]) {\n                int scoreExact = transitionCostAndDP(curDP, curWord, j, tmpDP);\n                int future = (remain > 1 ? bestOutApprox[j] / 2 : 0);\n                int score2 = scoreExact + future;\n                cand.push_back({score2, scoreExact, j});\n            }\n            sort(cand.begin(), cand.end(), [](const Cand& a, const Cand& b) {\n                if (a.score2 != b.score2) return a.score2 < b.score2;\n                if (a.scoreExact != b.scoreExact) return a.scoreExact < b.scoreExact;\n                return a.j < b.j;\n            });\n\n            int pickIdx = 0;\n            if (randomized) {\n                int lim = min<int>(topNext, cand.size());\n                pickIdx = uniform_int_distribution<int>(0, lim - 1)(rr);\n            }\n            int nxt = cand[pickIdx].j;\n\n            transitionCostAndDP(curDP, curWord, nxt, chosenDP);\n            curCnt = endCnt[nxt];\n            for (int e = 0; e < curCnt; e++) curDP[e] = chosenDP[e];\n\n            perm.push_back(nxt);\n            used[nxt] = 1;\n            curWord = nxt;\n        }\n        return perm;\n    }\n\n    vector<int> initEdgeGreedy(uint32_t seed, bool randomized) const {\n        struct E {\n            int u, v, cost, ovv;\n        };\n        vector<E> edges;\n        edges.reserve(M * (M - 1));\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) if (i != j) {\n                edges.push_back({i, j, edgeApprox[i][j], ov[i][j]});\n            }\n        }\n\n        mt19937 rr(seed);\n        if (randomized) shuffle(edges.begin(), edges.end(), rr);\n\n        stable_sort(edges.begin(), edges.end(), [&](const E& a, const E& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.ovv != b.ovv) return a.ovv > b.ovv;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        vector<int> in(M, -1), out(M, -1);\n        DSU dsu(M);\n        int used = 0;\n        for (auto& e : edges) {\n            if (out[e.u] != -1) continue;\n            if (in[e.v] != -1) continue;\n            if (dsu.same(e.u, e.v)) continue;\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n            used++;\n            if (used == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) if (in[i] == -1) {\n            head = i;\n            break;\n        }\n\n        vector<int> perm;\n        perm.reserve(M);\n        vector<char> seen(M, 0);\n        int cur = head;\n        while (cur != -1 && !seen[cur]) {\n            perm.push_back(cur);\n            seen[cur] = 1;\n            cur = out[cur];\n        }\n        for (int i = 0; i < M; i++) if (!seen[i]) perm.push_back(i);\n        return perm;\n    }\n\n    vector<int> initExactInsertion(uint32_t seed, bool randomized) const {\n        mt19937 rr(seed);\n        if (M == 1) return {0};\n\n        int pairKeep = randomized ? 14 : 8;\n        pairKeep = min<int>(pairKeep, exactPairList.size());\n\n        int choosePair = 0;\n        if (randomized) {\n            int lim = min<int>(3, pairKeep);\n            choosePair = uniform_int_distribution<int>(0, lim - 1)(rr);\n        }\n\n        int a = get<1>(exactPairList[choosePair]);\n        int b = get<2>(exactPairList[choosePair]);\n\n        vector<int> perm = {a, b};\n        vector<char> used(M, 0);\n        used[a] = used[b] = 1;\n\n        while ((int)perm.size() < M) {\n            struct Cand {\n                int inc, x, pos;\n            };\n            vector<Cand> global;\n            int keepPerX = randomized ? 2 : 1;\n\n            for (int x = 0; x < M; x++) if (!used[x]) {\n                vector<Cand> bests;\n                bests.reserve(keepPerX + 2);\n\n                auto push = [&](Cand c) {\n                    bests.push_back(c);\n                    sort(bests.begin(), bests.end(), [](const Cand& a, const Cand& b) {\n                        if (a.inc != b.inc) return a.inc < b.inc;\n                        if (a.x != b.x) return a.x < b.x;\n                        return a.pos < b.pos;\n                    });\n                    if ((int)bests.size() > keepPerX) bests.pop_back();\n                };\n\n                push({startApprox[x] + edgeApprox[x][perm[0]] - startApprox[perm[0]], x, 0});\n                for (int i = 1; i < (int)perm.size(); i++) {\n                    int inc = edgeApprox[perm[i - 1]][x] + edgeApprox[x][perm[i]] - edgeApprox[perm[i - 1]][perm[i]];\n                    push({inc, x, i});\n                }\n                push({edgeApprox[perm.back()][x], x, (int)perm.size()});\n\n                for (auto& c : bests) global.push_back(c);\n            }\n\n            sort(global.begin(), global.end(), [](const Cand& a, const Cand& b) {\n                if (a.inc != b.inc) return a.inc < b.inc;\n                if (a.x != b.x) return a.x < b.x;\n                return a.pos < b.pos;\n            });\n\n            int globalKeep = randomized ? 14 : 8;\n            globalKeep = min<int>(globalKeep, global.size());\n\n            vector<Cand> exactBest;\n            for (int t = 0; t < globalKeep; t++) {\n                auto c = global[t];\n                vector<int> np = perm;\n                np.insert(np.begin() + c.pos, c.x);\n                int ex = evalPerm(np);\n                exactBest.push_back({ex, c.x, c.pos});\n            }\n\n            sort(exactBest.begin(), exactBest.end(), [](const Cand& a, const Cand& b) {\n                if (a.inc != b.inc) return a.inc < b.inc;\n                if (a.x != b.x) return a.x < b.x;\n                return a.pos < b.pos;\n            });\n\n            int choose = 0;\n            if (randomized) {\n                int lim = min<int>(2, exactBest.size());\n                choose = uniform_int_distribution<int>(0, lim - 1)(rr);\n            }\n\n            auto c = exactBest[choose];\n            perm.insert(perm.begin() + c.pos, c.x);\n            used[c.x] = 1;\n        }\n\n        return perm;\n    }\n\n    // ---------- Approx deltas ----------\n\n    inline long long linkApprox(int prev, int cur) const {\n        if (cur == -1) return 0;\n        if (prev == -1) return startApprox[cur];\n        return edgeApprox[prev][cur];\n    }\n\n    long long blockRelocateDelta(const vector<int>& p, int a, int len, int b) const {\n        int n = (int)p.size();\n        int x0 = p[a];\n        int x1 = p[a + len - 1];\n        int A = (a > 0 ? p[a - 1] : -1);\n        int B = (a + len < n ? p[a + len] : -1);\n\n        auto qAt = [&](int idx) -> int {\n            if (idx < a) return p[idx];\n            return p[idx + len];\n        };\n\n        int qSize = n - len;\n        int C = (b > 0 ? qAt(b - 1) : -1);\n        int D = (b < qSize ? qAt(b) : -1);\n\n        long long delta = 0;\n        delta -= linkApprox(A, x0);\n        delta -= linkApprox(x1, B);\n        delta += linkApprox(A, B);\n\n        delta -= linkApprox(C, D);\n        delta += linkApprox(C, x0);\n        delta += linkApprox(x1, D);\n\n        return delta;\n    }\n\n    long long swapDelta(const vector<int>& p, int a, int b) const {\n        if (a == b) return 0;\n        if (a > b) swap(a, b);\n        int n = (int)p.size();\n\n        int A = p[a], B = p[b];\n        int pA = (a > 0 ? p[a - 1] : -1);\n        int nA = (a + 1 < n ? p[a + 1] : -1);\n        int pB = (b > 0 ? p[b - 1] : -1);\n        int nB = (b + 1 < n ? p[b + 1] : -1);\n\n        long long oldCost = 0, newCost = 0;\n\n        if (a + 1 == b) {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, A);\n            newCost += linkApprox(A, nB);\n        } else {\n            oldCost += linkApprox(pA, A);\n            oldCost += linkApprox(A, nA);\n            oldCost += linkApprox(pB, B);\n            oldCost += linkApprox(B, nB);\n\n            newCost += linkApprox(pA, B);\n            newCost += linkApprox(B, nA);\n            newCost += linkApprox(pB, A);\n            newCost += linkApprox(A, nB);\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyBlockRelocate(vector<int>& p, int a, int len, int b) const {\n        vector<int> block(p.begin() + a, p.begin() + a + len);\n        p.erase(p.begin() + a, p.begin() + a + len);\n        p.insert(p.begin() + b, block.begin(), block.end());\n    }\n\n    void applyMove(vector<int>& p, int type, int a, int b) const {\n        // 0: relocate len1\n        // 1: relocate len2\n        // 2: relocate len3\n        // 3: swap\n        if (type == 0) applyBlockRelocate(p, a, 1, b);\n        else if (type == 1) applyBlockRelocate(p, a, 2, b);\n        else if (type == 2) applyBlockRelocate(p, a, 3, b);\n        else swap(p[a], p[b]);\n    }\n\n    struct MoveCand {\n        long long d;\n        int type, a, b;\n    };\n\n    pair<vector<int>, int> localSearch(vector<int> perm, int curExact, int maxIter, int topK) {\n        int n = (int)perm.size();\n\n        for (int iter = 0; iter < maxIter && !timeup(0.06); iter++) {\n            vector<MoveCand> cand;\n            cand.reserve(n * n + max(0, (n - 1) * (n - 1)) + max(0, (n - 2) * (n - 2)) + n * (n - 1) / 2);\n\n            for (int a = 0; a < n; a++) {\n                for (int b = 0; b <= n - 1; b++) {\n                    if (b == a) continue;\n                    long long d = blockRelocateDelta(perm, a, 1, b);\n                    cand.push_back({d, 0, a, b});\n                }\n            }\n\n            if (n >= 2) {\n                for (int a = 0; a + 1 < n; a++) {\n                    for (int b = 0; b <= n - 2; b++) {\n                        if (b == a) continue;\n                        long long d = blockRelocateDelta(perm, a, 2, b);\n                        cand.push_back({d, 1, a, b});\n                    }\n                }\n            }\n\n            if (n >= 3) {\n                for (int a = 0; a + 2 < n; a++) {\n                    for (int b = 0; b <= n - 3; b++) {\n                        if (b == a) continue;\n                        long long d = blockRelocateDelta(perm, a, 3, b);\n                        cand.push_back({d, 2, a, b});\n                    }\n                }\n            }\n\n            for (int a = 0; a < n; a++) {\n                for (int b = a + 1; b < n; b++) {\n                    long long d = swapDelta(perm, a, b);\n                    cand.push_back({d, 3, a, b});\n                }\n            }\n\n            auto comp = [](const MoveCand& x, const MoveCand& y) {\n                if (x.d != y.d) return x.d < y.d;\n                if (x.type != y.type) return x.type < y.type;\n                if (x.a != y.a) return x.a < y.a;\n                return x.b < y.b;\n            };\n\n            int K = min<int>(topK, cand.size());\n            if (K == 0) break;\n            if (K < (int)cand.size()) {\n                nth_element(cand.begin(), cand.begin() + K, cand.end(), comp);\n                cand.resize(K);\n            }\n            sort(cand.begin(), cand.end(), comp);\n\n            bool improved = false;\n            int bestExact = curExact;\n            vector<int> bestPerm;\n\n            for (auto& mv : cand) {\n                if (timeup(0.05)) break;\n                vector<int> np = perm;\n                applyMove(np, mv.type, mv.a, mv.b);\n                int ex = evalPerm(np);\n                if (ex < bestExact) {\n                    bestExact = ex;\n                    bestPerm.swap(np);\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n            perm.swap(bestPerm);\n            curExact = bestExact;\n        }\n\n        return {perm, curExact};\n    }\n\n    // ---------- Cheap exact polishing ----------\n\n    pair<vector<int>, int> polishTriples(vector<int> perm, int curExact, int passes) {\n        int n = (int)perm.size();\n        if (n < 3) return {perm, curExact};\n\n        for (int pass = 0; pass < passes && !timeup(0.10); pass++) {\n            bool any = false;\n            for (int l = 0; l + 3 <= n && !timeup(0.10); l++) {\n                array<int, 3> cur = {perm[l], perm[l + 1], perm[l + 2]};\n                vector<int> base = {cur[0], cur[1], cur[2]};\n                sort(base.begin(), base.end());\n\n                int bestEx = curExact;\n                array<int, 3> bestSeg = cur;\n\n                do {\n                    array<int, 3> seg = {base[0], base[1], base[2]};\n                    if (seg == cur) continue;\n                    vector<int> np = perm;\n                    np[l] = seg[0];\n                    np[l + 1] = seg[1];\n                    np[l + 2] = seg[2];\n                    int ex = evalPerm(np);\n                    if (ex < bestEx) {\n                        bestEx = ex;\n                        bestSeg = seg;\n                    }\n                } while (next_permutation(base.begin(), base.end()));\n\n                if (bestEx < curExact) {\n                    perm[l] = bestSeg[0];\n                    perm[l + 1] = bestSeg[1];\n                    perm[l + 2] = bestSeg[2];\n                    curExact = bestEx;\n                    any = true;\n                }\n            }\n            if (!any) break;\n        }\n\n        return {perm, curExact};\n    }\n\n    pair<vector<int>, int> polishQuads(vector<int> perm, int curExact, int passes) {\n        int n = (int)perm.size();\n        if (n < 4) return {perm, curExact};\n\n        for (int pass = 0; pass < passes && !timeup(0.08); pass++) {\n            bool any = false;\n            for (int l = 0; l + 4 <= n && !timeup(0.08); l++) {\n                array<int, 4> cur = {perm[l], perm[l + 1], perm[l + 2], perm[l + 3]};\n                vector<int> base = {cur[0], cur[1], cur[2], cur[3]};\n                sort(base.begin(), base.end());\n\n                int bestEx = curExact;\n                array<int, 4> bestSeg = cur;\n\n                do {\n                    array<int, 4> seg = {base[0], base[1], base[2], base[3]};\n                    if (seg == cur) continue;\n                    vector<int> np = perm;\n                    np[l] = seg[0];\n                    np[l + 1] = seg[1];\n                    np[l + 2] = seg[2];\n                    np[l + 3] = seg[3];\n                    int ex = evalPerm(np);\n                    if (ex < bestEx) {\n                        bestEx = ex;\n                        bestSeg = seg;\n                    }\n                } while (next_permutation(base.begin(), base.end()));\n\n                if (bestEx < curExact) {\n                    perm[l] = bestSeg[0];\n                    perm[l + 1] = bestSeg[1];\n                    perm[l + 2] = bestSeg[2];\n                    perm[l + 3] = bestSeg[3];\n                    curExact = bestEx;\n                    any = true;\n                }\n            }\n            if (!any) break;\n        }\n\n        return {perm, curExact};\n    }\n\n    // ---------- ILS ----------\n\n    void randomKick(vector<int>& perm, mt19937& rr, int cnt) const {\n        int n = (int)perm.size();\n        for (int t = 0; t < cnt; t++) {\n            int typ = uniform_int_distribution<int>(0, 3)(rr);\n            if (typ == 0) {\n                int a = uniform_int_distribution<int>(0, n - 1)(rr);\n                int b = uniform_int_distribution<int>(0, n - 1)(rr);\n                if (a != b) swap(perm[a], perm[b]);\n            } else if (typ == 1) {\n                int a = uniform_int_distribution<int>(0, n - 1)(rr);\n                int b = uniform_int_distribution<int>(0, n - 1)(rr);\n                applyBlockRelocate(perm, a, 1, b);\n            } else if (typ == 2) {\n                if (n >= 2) {\n                    int a = uniform_int_distribution<int>(0, n - 2)(rr);\n                    int b = uniform_int_distribution<int>(0, n - 2)(rr);\n                    applyBlockRelocate(perm, a, 2, b);\n                }\n            } else {\n                if (n >= 3) {\n                    int a = uniform_int_distribution<int>(0, n - 3)(rr);\n                    int b = uniform_int_distribution<int>(0, n - 3)(rr);\n                    applyBlockRelocate(perm, a, 3, b);\n                }\n            }\n        }\n    }\n\n    // ---------- Final exact path ----------\n\n    pair<int, vector<int>> exactPathForString(const string& s) const {\n        int L = (int)s.size();\n        vector<vector<int>> parent(L);\n\n        const auto& firstPos = occ[s[0] - 'A'];\n        vector<int> dpPrev(firstPos.size());\n        parent[0].assign(firstPos.size(), -1);\n        for (int i = 0; i < (int)firstPos.size(); i++) {\n            dpPrev[i] = man[startPos][firstPos[i]] + 1;\n        }\n\n        for (int t = 1; t < L; t++) {\n            const auto& prevPos = occ[s[t - 1] - 'A'];\n            const auto& curPos = occ[s[t] - 'A'];\n            vector<int> dpCur(curPos.size(), INF);\n            parent[t].assign(curPos.size(), -1);\n\n            for (int ci = 0; ci < (int)curPos.size(); ci++) {\n                int q = curPos[ci];\n                int best = INF, bestp = -1;\n                for (int pi = 0; pi < (int)prevPos.size(); pi++) {\n                    int cand = dpPrev[pi] + man[prevPos[pi]][q] + 1;\n                    if (cand < best) {\n                        best = cand;\n                        bestp = pi;\n                    }\n                }\n                dpCur[ci] = best;\n                parent[t][ci] = bestp;\n            }\n            dpPrev.swap(dpCur);\n        }\n\n        int best = INF, idx = -1;\n        for (int i = 0; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < best) {\n                best = dpPrev[i];\n                idx = i;\n            }\n        }\n\n        vector<int> path(L);\n        path[L - 1] = occ[s[L - 1] - 'A'][idx];\n        for (int t = L - 1; t >= 1; t--) {\n            idx = parent[t][idx];\n            path[t - 1] = occ[s[t - 1] - 'A'][idx];\n        }\n        return {best, path};\n    }\n\n    void solve() {\n        t0 = chrono::steady_clock::now();\n\n        readInput();\n        buildSeed();\n        precomputeKeyboard();\n        precomputeOverlaps();\n        precomputeMatrices();\n        precomputeExactPairs();\n\n        vector<int> startOrder(M), pairLeadOrder(M);\n        iota(startOrder.begin(), startOrder.end(), 0);\n        iota(pairLeadOrder.begin(), pairLeadOrder.end(), 0);\n\n        sort(startOrder.begin(), startOrder.end(), [&](int a, int b) {\n            if (startApprox[a] != startApprox[b]) return startApprox[a] < startApprox[b];\n            return a < b;\n        });\n        sort(pairLeadOrder.begin(), pairLeadOrder.end(), [&](int a, int b) {\n            if (bestPairFrom[a] != bestPairFrom[b]) return bestPairFrom[a] < bestPairFrom[b];\n            return a < b;\n        });\n\n        struct SeedCand {\n            vector<int> perm;\n            int exact;\n        };\n        vector<SeedCand> seeds;\n\n        auto addSeed = [&](vector<int> p) {\n            int ex = evalPerm(p);\n            seeds.push_back({move(p), ex});\n        };\n\n        vector<int> detStarts;\n        auto addStart = [&](int x) {\n            for (int y : detStarts) if (y == x) return;\n            detStarts.push_back(x);\n        };\n\n        for (int i = 0; i < 4 && (int)detStarts.size() < 4; i++) {\n            if (i < M) addStart(startOrder[i]);\n            if ((int)detStarts.size() < 4 && i < M) addStart(pairLeadOrder[i]);\n        }\n        for (int i = 0; i < M && (int)detStarts.size() < 4; i++) addStart(i);\n\n        for (int i = 0; i < (int)detStarts.size(); i++) {\n            addSeed(initGreedyAppend(detStarts[i], baseSeed + 11 + i, false, 4));\n        }\n\n        {\n            mt19937 rr(baseSeed + 100);\n            int lim1 = min(10, M);\n            int lim2 = min(12, M);\n            for (int z = 0; z < 4 && !timeup(0.55); z++) {\n                bool usePairLead = uniform_int_distribution<int>(0, 1)(rr);\n                int first;\n                if (usePairLead) {\n                    first = pairLeadOrder[uniform_int_distribution<int>(0, lim2 - 1)(rr)];\n                } else {\n                    first = startOrder[uniform_int_distribution<int>(0, lim1 - 1)(rr)];\n                }\n                addSeed(initGreedyAppend(first, baseSeed + 21 + z, true, 5));\n            }\n        }\n\n        if (!timeup(0.46)) addSeed(initExactInsertion(baseSeed + 31, false));\n        if (!timeup(0.44)) addSeed(initExactInsertion(baseSeed + 32, true));\n        if (!timeup(0.42)) addSeed(initExactInsertion(baseSeed + 33, true));\n\n        if (!timeup(0.38)) addSeed(initEdgeGreedy(baseSeed + 41, false));\n        if (!timeup(0.36)) addSeed(initEdgeGreedy(baseSeed + 42, true));\n\n        sort(seeds.begin(), seeds.end(), [](const SeedCand& a, const SeedCand& b) {\n            return a.exact < b.exact;\n        });\n\n        vector<int> bestPerm = seeds[0].perm;\n        int bestExact = seeds[0].exact;\n\n        int topSeedCnt = min<int>(4, seeds.size());\n        for (int i = 0; i < topSeedCnt && !timeup(0.24); i++) {\n            int K = (elapsed() < 1.02 ? 2200 : 1600);\n            auto cur = localSearch(seeds[i].perm, seeds[i].exact, 7, K);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        if (!timeup(0.18)) {\n            auto cur = polishTriples(bestPerm, bestExact, 2);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        if (!timeup(0.14)) {\n            auto cur = polishQuads(bestPerm, bestExact, 1);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        if (!timeup(0.11)) {\n            auto cur = localSearch(bestPerm, bestExact, 3, 1350);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        mt19937 rr(baseSeed + 999);\n        int noImprove = 0;\n        while (!timeup(0.08)) {\n            vector<int> p = bestPerm;\n            int kickCnt = (noImprove < 3 ? 2 : (noImprove < 7 ? 4 : 6));\n            randomKick(p, rr, kickCnt);\n            int ex = evalPerm(p);\n\n            int K = (elapsed() < 1.42 ? 1150 : 700);\n            auto cur = localSearch(move(p), ex, 4, K);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n                noImprove = 0;\n\n                if (!timeup(0.07)) {\n                    auto pol = polishTriples(bestPerm, bestExact, 1);\n                    if (pol.second < bestExact) {\n                        bestExact = pol.second;\n                        bestPerm = move(pol.first);\n                    }\n                }\n            } else {\n                noImprove++;\n                if (noImprove >= 8 && elapsed() > 1.58) break;\n            }\n        }\n\n        if (!timeup(0.03)) {\n            auto cur = polishTriples(bestPerm, bestExact, 1);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n        if (!timeup(0.02)) {\n            auto cur = polishQuads(bestPerm, bestExact, 1);\n            if (cur.second < bestExact) {\n                bestExact = cur.second;\n                bestPerm = move(cur.first);\n            }\n        }\n\n        string finalS = buildString(bestPerm);\n        auto [finalCost, path] = exactPathForString(finalS);\n\n        for (int pos : path) {\n            cout << (pos / N) << ' ' << (pos % N) << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXQ = 160;\nstatic constexpr int WORDS = 7;   // 7*64 = 448 >= 400\nstatic constexpr int MAXD_BEAM = 64;\n\nusing ull = unsigned long long;\nusing Mask = array<ull, WORDS>;\n\nstruct Placement {\n    int di = 0, dj = 0;\n    Mask mask{};\n    array<unsigned char, MAXQ> contrib{};\n};\n\nstruct Field {\n    int sz = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> pls;\n};\n\nstruct State {\n    vector<int> choice;\n    array<short, MAXQ> setsum{};\n    vector<short> drillsum;\n    int pen = 0;\n    double div = 0.0;\n};\n\nstruct WeightedStates {\n    bool plausible = false;\n    int bestPen = INT_MAX;\n    vector<int> idx;\n    vector<double> w;\n    double sumW = 0.0;\n};\n\nstruct UnionSummary {\n    bool hasPlausible = false;\n    int bestPen = INT_MAX;\n    int distinctUnionCount = 0;\n\n    vector<Mask> masks;\n    vector<double> weights;\n\n    Mask bestMask{};\n    Mask must1{};\n    Mask maybe1{};\n\n    double bestWeight = 0.0;\n\n    vector<int> ambiguous;\n\n    vector<double> supportProb;\n    vector<double> supportVar;\n    vector<double> countVar;\n\n    double maxCellScore = -1.0;\n    int bestCell = -1;\n};\n\nstruct Solver {\n    int N, M, NN;\n    double eps, alpha;\n    int totalArea = 0;\n    int maxOps, ops = 0;\n\n    vector<Field> fields;\n\n    int Qcur = 0;\n    vector<vector<int>> queryCells;\n    vector<Mask> queryMasks;\n    vector<int> qSize, qResp;\n    vector<char> qKnown;\n    vector<vector<double>> qScore;\n\n    vector<array<int,4>> cellQids;\n\n    vector<int> drilledCells, drilledObs;\n    vector<int> cellObs;\n    vector<char> drilledFlag;\n\n    vector<State> pool;\n    vector<Mask> rejectedMasks;\n\n    vector<Mask> rowParityMask, colParityMask, checkerMask, rowMod3Mask, colMod3Mask;\n\n    mt19937_64 rng;\n    chrono::steady_clock::time_point stTime;\n    double compLog2 = 0.0;\n    int adaptiveQueriesUsed = 0;\n    int exactBeamRuns = 0;\n\n    Solver(): rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {}\n\n    // ---------- mask helpers ----------\n    static inline void mask_clear(Mask &m) { m.fill(0); }\n    static inline void mask_set(Mask &m, int idx) { m[idx >> 6] |= (1ULL << (idx & 63)); }\n    static inline bool mask_test(const Mask &m, int idx) { return (m[idx >> 6] >> (idx & 63)) & 1ULL; }\n    static inline void mask_or_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] |= b[i]; }\n    static inline void mask_and_eq(Mask &a, const Mask &b) { for (int i = 0; i < WORDS; i++) a[i] &= b[i]; }\n    static inline Mask mask_and(const Mask &a, const Mask &b) { Mask c = a; mask_and_eq(c, b); return c; }\n    static inline Mask mask_xor(const Mask &a, const Mask &b) {\n        Mask c{};\n        for (int i = 0; i < WORDS; i++) c[i] = a[i] ^ b[i];\n        return c;\n    }\n    static inline Mask mask_andnot(const Mask &a, const Mask &b) {\n        Mask c{};\n        for (int i = 0; i < WORDS; i++) c[i] = a[i] & ~b[i];\n        return c;\n    }\n    static inline int mask_popcount(const Mask &m) {\n        int s = 0;\n        for (int i = 0; i < WORDS; i++) s += __builtin_popcountll(m[i]);\n        return s;\n    }\n    static inline int intersect_count(const Mask &a, const Mask &b) {\n        int s = 0;\n        for (int i = 0; i < WORDS; i++) s += __builtin_popcountll(a[i] & b[i]);\n        return s;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - stTime).count();\n    }\n\n    bool better(int p1, double d1, int p2, double d2) const {\n        if (p1 != p2) return p1 < p2;\n        return d1 + 1e-12 < d2;\n    }\n\n    int rand_int(int lim) {\n        return int(rng() % (uint64_t)lim);\n    }\n\n    int activeQCount() const {\n        int c = 0;\n        for (int q = 0; q < Qcur; q++) c += qKnown[q];\n        return c;\n    }\n\n    bool can_spend_ops(int extraOps) const {\n        int needFallback = (NN - (int)drilledCells.size()) + 1;\n        return ops + extraOps + needFallback <= maxOps;\n    }\n\n    bool is_rejected_mask(const Mask &m) const {\n        for (const auto &x : rejectedMasks) if (x == m) return true;\n        return false;\n    }\n\n    vector<int> cells_from_mask(const Mask &m) const {\n        vector<int> cells;\n        cells.reserve(mask_popcount(m));\n        for (int idx = 0; idx < NN; idx++) if (mask_test(m, idx)) cells.push_back(idx);\n        return cells;\n    }\n\n    // ---------- probability ----------\n    static double norm_cdf(double x) {\n        static const double INV_SQRT2 = 0.707106781186547524400844362104849039;\n        return 0.5 * erfc(-x * INV_SQRT2);\n    }\n\n    static double rounded_normal_nll(int y, double mu, double sigma) {\n        double prob;\n        if (sigma < 1e-12) {\n            int z = max(0, (int)llround(mu));\n            prob = (z == y ? 1.0 : 0.0);\n        } else if (y == 0) {\n            double hi = (0.5 - mu) / sigma;\n            prob = norm_cdf(hi);\n        } else {\n            double lo = (y - 0.5 - mu) / sigma;\n            double hi = (y + 0.5 - mu) / sigma;\n            prob = norm_cdf(hi) - norm_cdf(lo);\n        }\n        if (prob < 1e-300) prob = 1e-300;\n        return -log(prob);\n    }\n\n    // ---------- I/O ----------\n    void read_input() {\n        cin >> N >> M >> eps;\n        NN = N * N;\n        maxOps = 2 * NN;\n        alpha = 1.0 - 2.0 * eps;\n\n        fields.resize(M);\n        for (int k = 0; k < M; k++) {\n            int d;\n            cin >> d;\n            fields[k].sz = d;\n            fields[k].rel.resize(d);\n            int mxr = 0, mxc = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[k].rel[t] = {i, j};\n                mxr = max(mxr, i);\n                mxc = max(mxc, j);\n            }\n            fields[k].h = mxr + 1;\n            fields[k].w = mxc + 1;\n            totalArea += d;\n        }\n\n        cellObs.assign(NN, -1);\n        drilledFlag.assign(NN, 0);\n\n        queryCells.assign(MAXQ, {});\n        queryMasks.assign(MAXQ, {});\n        qSize.assign(MAXQ, 0);\n        qResp.assign(MAXQ, 0);\n        qKnown.assign(MAXQ, 0);\n        qScore.assign(MAXQ, vector<double>(totalArea + 1, 0.0));\n    }\n\n    int ask_set_query(const vector<int> &cells) {\n        cout << \"q \" << cells.size();\n        for (int idx : cells) cout << ' ' << (idx / N) << ' ' << (idx % N);\n        cout << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    int ask_drill(int idx) {\n        cout << \"q 1 \" << (idx / N) << ' ' << (idx % N) << '\\n' << flush;\n        int x;\n        cin >> x;\n        ops++;\n        return x;\n    }\n\n    bool answer_mask_raw(const Mask &mask) {\n        vector<int> cells;\n        cells.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) if (mask_test(mask, idx)) cells.push_back(idx);\n\n        cout << \"a \" << cells.size();\n        for (int idx : cells) cout << ' ' << (idx / N) << ' ' << (idx % N);\n        cout << '\\n' << flush;\n        int res;\n        cin >> res;\n        ops++;\n        return res == 1;\n    }\n\n    bool submit_guess(const Mask &mask) {\n        if (is_rejected_mask(mask)) return false;\n        bool ok = answer_mask_raw(mask);\n        if (!ok) rejectedMasks.push_back(mask);\n        return ok;\n    }\n\n    // ---------- setup ----------\n    void build_queries() {\n        // base queries:\n        // [0, N) row\n        // [N, 2N) col\n        // [2N, 2N+4) mod2\n        // [2N+4, 2N+13) mod3\n        Qcur = 2 * N + 13;\n        cellQids.resize(NN);\n\n        rowParityMask.assign(2, Mask{});\n        colParityMask.assign(2, Mask{});\n        checkerMask.assign(2, Mask{});\n        rowMod3Mask.assign(3, Mask{});\n        colMod3Mask.assign(3, Mask{});\n\n        for (auto &m : rowParityMask) mask_clear(m);\n        for (auto &m : colParityMask) mask_clear(m);\n        for (auto &m : checkerMask) mask_clear(m);\n        for (auto &m : rowMod3Mask) mask_clear(m);\n        for (auto &m : colMod3Mask) mask_clear(m);\n\n        for (int q = 0; q < Qcur; q++) {\n            queryCells[q].clear();\n            mask_clear(queryMasks[q]);\n        }\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int idx = i * N + j;\n                int q0 = i;\n                int q1 = N + j;\n                int q2 = 2 * N + (i & 1) * 2 + (j & 1);\n                int q3 = 2 * N + 4 + (i % 3) * 3 + (j % 3);\n                cellQids[idx] = {q0, q1, q2, q3};\n\n                queryCells[q0].push_back(idx);\n                queryCells[q1].push_back(idx);\n                queryCells[q2].push_back(idx);\n                queryCells[q3].push_back(idx);\n\n                mask_set(rowParityMask[i & 1], idx);\n                mask_set(colParityMask[j & 1], idx);\n                mask_set(checkerMask[(i + j) & 1], idx);\n                mask_set(rowMod3Mask[i % 3], idx);\n                mask_set(colMod3Mask[j % 3], idx);\n            }\n        }\n\n        for (int q = 0; q < Qcur; q++) {\n            for (int idx : queryCells[q]) mask_set(queryMasks[q], idx);\n            qSize[q] = (int)queryCells[q].size();\n        }\n    }\n\n    void precompute_placements() {\n        compLog2 = 0.0;\n        for (int k = 0; k < M; k++) {\n            auto &f = fields[k];\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                    mask_clear(p.mask);\n                    p.contrib.fill(0);\n\n                    for (auto [ri, rj] : f.rel) {\n                        int ai = di + ri;\n                        int aj = dj + rj;\n                        int idx = ai * N + aj;\n                        mask_set(p.mask, idx);\n                        auto &arr = cellQids[idx];\n                        for (int t = 0; t < 4; t++) p.contrib[arr[t]]++;\n                    }\n                    f.pls.push_back(p);\n                }\n            }\n            compLog2 += log2((double)max(1, (int)f.pls.size()));\n        }\n    }\n\n    void register_query_response(int q, int y) {\n        qKnown[q] = 1;\n        qResp[q] = y;\n\n        double sigma = sqrt((double)qSize[q] * eps * (1.0 - eps));\n        for (int v = 0; v <= totalArea; v++) {\n            double mu = eps * qSize[q] + alpha * v;\n            qScore[q][v] = rounded_normal_nll(y, mu, sigma);\n        }\n    }\n\n    void activate_queries(int l, int r) {\n        for (int q = l; q < r; q++) {\n            if (qKnown[q]) continue;\n            if (!can_spend_ops(1)) return;\n            int y = ask_set_query(queryCells[q]);\n            register_query_response(q, y);\n        }\n    }\n\n    bool add_adaptive_query(const Mask &m) {\n        int k = mask_popcount(m);\n        if (k < 2 || Qcur >= MAXQ) return false;\n        if (!can_spend_ops(1)) return false;\n        for (int q = 0; q < Qcur; q++) if (queryMasks[q] == m) return false;\n\n        int q = Qcur++;\n        queryMasks[q] = m;\n        queryCells[q] = cells_from_mask(m);\n        qSize[q] = k;\n\n        for (auto &f : fields) {\n            for (auto &pl : f.pls) {\n                pl.contrib[q] = (unsigned char)intersect_count(pl.mask, m);\n            }\n        }\n\n        int y = ask_set_query(queryCells[q]);\n        register_query_response(q, y);\n        adaptiveQueriesUsed++;\n        return true;\n    }\n\n    // ---------- state build / local search ----------\n    State build_state(const vector<int> &choice) {\n        State st;\n        st.choice = choice;\n        st.setsum.fill(0);\n\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[choice[k]];\n            for (int q = 0; q < Qcur; q++) st.setsum[q] += pl.contrib[q];\n        }\n\n        st.div = 0.0;\n        for (int q = 0; q < Qcur; q++) if (qKnown[q]) st.div += qScore[q][st.setsum[q]];\n\n        int D = (int)drilledCells.size();\n        st.drillsum.assign(D, 0);\n        st.pen = 0;\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int s = 0;\n            for (int k = 0; k < M; k++) s += (int)mask_test(fields[k].pls[choice[k]].mask, idx);\n            st.drillsum[t] = (short)s;\n            int d = s - drilledObs[t];\n            st.pen += d * d;\n        }\n        return st;\n    }\n\n    void apply_move(State &st, int k, int newPid) {\n        int oldPid = st.choice[k];\n        if (oldPid == newPid) return;\n\n        const auto &oldPl = fields[k].pls[oldPid];\n        const auto &newPl = fields[k].pls[newPid];\n\n        for (int q = 0; q < Qcur; q++) {\n            int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n            if (!diff) continue;\n            int oldv = st.setsum[q];\n            int newv = oldv + diff;\n            if (qKnown[q]) st.div += qScore[q][newv] - qScore[q][oldv];\n            st.setsum[q] = (short)newv;\n        }\n\n        int D = (int)drilledCells.size();\n        for (int t = 0; t < D; t++) {\n            int idx = drilledCells[t];\n            int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n            if (!diff) continue;\n            int oldv = st.drillsum[t];\n            int newv = oldv + diff;\n            int before = oldv - drilledObs[t];\n            int after = newv - drilledObs[t];\n            st.pen += after * after - before * before;\n            st.drillsum[t] = (short)newv;\n        }\n\n        st.choice[k] = newPid;\n    }\n\n    void hill_climb(State &st, int sweeps) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            bool changed = false;\n            shuffle(ord.begin(), ord.end(), rng);\n\n            for (int zz = 0; zz < M; zz++) {\n                int k = ord[zz];\n                int oldPid = st.choice[k];\n                const auto &oldPl = fields[k].pls[oldPid];\n                int bestPid = oldPid;\n                int bestPen = st.pen;\n                double bestDiv = st.div;\n\n                int D = (int)drilledCells.size();\n\n                for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                    if (pid == oldPid) continue;\n                    const auto &newPl = fields[k].pls[pid];\n\n                    int candPen = st.pen;\n                    double candDiv = st.div;\n\n                    for (int q = 0; q < Qcur; q++) {\n                        int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n                        if (!diff) continue;\n                        int oldv = st.setsum[q];\n                        int newv = oldv + diff;\n                        if (qKnown[q]) candDiv += qScore[q][newv] - qScore[q][oldv];\n                    }\n\n                    for (int t = 0; t < D; t++) {\n                        int idx = drilledCells[t];\n                        int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n                        if (!diff) continue;\n                        int oldv = st.drillsum[t];\n                        int newv = oldv + diff;\n                        int before = oldv - drilledObs[t];\n                        int after = newv - drilledObs[t];\n                        candPen += after * after - before * before;\n                    }\n\n                    if (better(candPen, candDiv, bestPen, bestDiv)) {\n                        bestPen = candPen;\n                        bestDiv = candDiv;\n                        bestPid = pid;\n                    }\n                }\n\n                if (bestPid != oldPid) {\n                    apply_move(st, k, bestPid);\n                    changed = true;\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> random_seed() {\n        vector<int> choice(M);\n        for (int k = 0; k < M; k++) choice[k] = rand_int((int)fields[k].pls.size());\n        return choice;\n    }\n\n    vector<int> greedy_seed() {\n        vector<int> choice(M, 0);\n        array<short, MAXQ> cur{};\n        cur.fill(0);\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int id = 0; id < M; id++) {\n            int k = ord[id];\n            int bestPid = 0;\n            double bestDelta = 1e100;\n\n            for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                const auto &pl = fields[k].pls[pid];\n                double delta = 0.0;\n                for (int q = 0; q < Qcur; q++) {\n                    if (!qKnown[q]) continue;\n                    int c = pl.contrib[q];\n                    if (!c) continue;\n                    int oldv = cur[q];\n                    int newv = oldv + c;\n                    delta += qScore[q][newv] - qScore[q][oldv];\n                }\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestPid = pid;\n                }\n            }\n\n            choice[k] = bestPid;\n            const auto &pl = fields[k].pls[bestPid];\n            for (int q = 0; q < Qcur; q++) cur[q] += pl.contrib[q];\n        }\n        return choice;\n    }\n\n    vector<int> perturbed_seed() {\n        if (pool.empty()) return random_seed();\n        int baseCnt = min(6, (int)pool.size());\n        vector<int> choice = pool[rand_int(baseCnt)].choice;\n\n        int changes = 1 + rand_int(max(1, min(5, M)));\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng);\n\n        for (int t = 0; t < changes; t++) {\n            int k = ord[t];\n            int sz = (int)fields[k].pls.size();\n            if (sz <= 1) continue;\n            int cur = choice[k];\n            int np = rand_int(sz - 1);\n            if (np >= cur) np++;\n            choice[k] = np;\n        }\n        return choice;\n    }\n\n    vector<int> crossover_seed() {\n        if ((int)pool.size() < 2) return random_seed();\n        int baseCnt = min(8, (int)pool.size());\n        int a = rand_int(baseCnt);\n        int b = rand_int(baseCnt - 1);\n        if (b >= a) b++;\n        vector<int> child(M);\n        ull r = rng();\n        for (int k = 0; k < M; k++) child[k] = ((r >> (k & 63)) & 1ULL) ? pool[a].choice[k] : pool[b].choice[k];\n        if (rand_int(3) == 0) {\n            int k = rand_int(M);\n            int sz = (int)fields[k].pls.size();\n            if (sz > 1) child[k] = rand_int(sz);\n        }\n        return child;\n    }\n\n    bool contains_choice(const vector<vector<int>> &vv, const vector<int> &x) {\n        for (const auto &v : vv) if (v == x) return true;\n        return false;\n    }\n\n    void optimize_pool(int randomCnt, int pertCnt, int sweeps, bool useGreedy) {\n        vector<vector<int>> seeds;\n\n        for (const auto &st : pool) {\n            if (!contains_choice(seeds, st.choice)) seeds.push_back(st.choice);\n        }\n\n        if (useGreedy) {\n            for (int t = 0; t < 6; t++) {\n                auto s = greedy_seed();\n                if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n            }\n        }\n\n        int crossCnt = min(8, max(0, (int)pool.size() - 1));\n        for (int t = 0; t < crossCnt; t++) {\n            auto s = crossover_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        for (int t = 0; t < pertCnt; t++) {\n            auto s = perturbed_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        for (int t = 0; t < randomCnt; t++) {\n            auto s = random_seed();\n            if (!contains_choice(seeds, s)) seeds.push_back(move(s));\n        }\n\n        if (seeds.empty()) seeds.push_back(random_seed());\n\n        vector<State> cands;\n        cands.reserve(seeds.size());\n        for (auto &seed : seeds) {\n            State st = build_state(seed);\n            hill_climb(st, sweeps);\n            cands.push_back(move(st));\n        }\n\n        sort(cands.begin(), cands.end(), [&](const State &a, const State &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        pool.clear();\n        for (auto &st : cands) {\n            bool dup = false;\n            for (auto &kept : pool) {\n                if (kept.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) pool.push_back(move(st));\n            if ((int)pool.size() >= 28) break;\n        }\n    }\n\n    // ---------- beam helpers ----------\n    bool zero_compatible(int k, int pid) const {\n        const auto &pl = fields[k].pls[pid];\n        for (int t = 0; t < (int)drilledCells.size(); t++) {\n            if (drilledObs[t] == 0 && mask_test(pl.mask, drilledCells[t])) return false;\n        }\n        return true;\n    }\n\n    bool merge_states(vector<State> extra) {\n        if (extra.empty()) return false;\n        int oldPen = pool.empty() ? INT_MAX : pool[0].pen;\n        double oldDiv = pool.empty() ? 1e100 : pool[0].div;\n\n        vector<State> merged = pool;\n        for (auto &st : extra) {\n            bool dup = false;\n            for (auto &x : merged) {\n                if (x.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) merged.push_back(move(st));\n        }\n\n        sort(merged.begin(), merged.end(), [&](const State &a, const State &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        vector<State> uniq;\n        uniq.reserve(min(32, (int)merged.size()));\n        for (auto &st : merged) {\n            bool dup = false;\n            for (auto &u : uniq) {\n                if (u.choice == st.choice) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) uniq.push_back(move(st));\n            if ((int)uniq.size() >= 32) break;\n        }\n\n        bool improved = !pool.empty() ? better(uniq[0].pen, uniq[0].div, oldPen, oldDiv) : !uniq.empty();\n        pool.swap(uniq);\n        return improved;\n    }\n\n    vector<int> best_alternatives_from_base(const State &base, int k, const vector<char> &used, int need) {\n        struct Cand {\n            int pid;\n            int pen;\n            double div;\n        };\n        vector<Cand> vec;\n        vec.reserve(fields[k].pls.size());\n\n        int oldPid = base.choice[k];\n        const auto &oldPl = fields[k].pls[oldPid];\n        int D = (int)drilledCells.size();\n\n        for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n            if (used[pid]) continue;\n            if (!zero_compatible(k, pid)) continue;\n            if (pid == oldPid) continue;\n            const auto &newPl = fields[k].pls[pid];\n\n            int candPen = base.pen;\n            double candDiv = base.div;\n\n            for (int q = 0; q < Qcur; q++) {\n                if (!qKnown[q]) continue;\n                int diff = (int)newPl.contrib[q] - (int)oldPl.contrib[q];\n                if (!diff) continue;\n                int oldv = base.setsum[q];\n                int newv = oldv + diff;\n                candDiv += qScore[q][newv] - qScore[q][oldv];\n            }\n\n            for (int t = 0; t < D; t++) {\n                int idx = drilledCells[t];\n                int diff = (int)mask_test(newPl.mask, idx) - (int)mask_test(oldPl.mask, idx);\n                if (!diff) continue;\n                int oldv = base.drillsum[t];\n                int newv = oldv + diff;\n                int before = oldv - drilledObs[t];\n                int after = newv - drilledObs[t];\n                candPen += after * after - before * before;\n            }\n\n            vec.push_back({pid, candPen, candDiv});\n        }\n\n        sort(vec.begin(), vec.end(), [&](const Cand &a, const Cand &b) {\n            if (a.pen != b.pen) return a.pen < b.pen;\n            return a.div < b.div;\n        });\n\n        vector<int> res;\n        for (int i = 0; i < (int)vec.size() && (int)res.size() < need; i++) res.push_back(vec[i].pid);\n        return res;\n    }\n\n    bool beam_merge_from_candidates(const vector<vector<int>> &candP, int beamWidth, int localKeep) {\n        if (exactBeamRuns >= 5) return false;\n        if (elapsed() > 2.40) return false;\n        if ((int)drilledCells.size() > MAXD_BEAM) return false;\n\n        vector<int> actQ;\n        for (int q = 0; q < Qcur; q++) if (qKnown[q]) actQ.push_back(q);\n        int AQ = (int)actQ.size();\n        int D = (int)drilledCells.size();\n        if (AQ == 0) return false;\n\n        for (int k = 0; k < M; k++) if (candP[k].empty()) return false;\n\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (candP[a].size() != candP[b].size()) return candP[a].size() < candP[b].size();\n            return fields[a].sz > fields[b].sz;\n        });\n\n        vector<vector<unsigned short>> fMinQ(M, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned short>> fMaxQ(M, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned char>> fMinD(M, vector<unsigned char>(D, 0));\n        vector<vector<unsigned char>> fMaxD(M, vector<unsigned char>(D, 0));\n\n        for (int pos = 0; pos < M; pos++) {\n            int k = order[pos];\n            for (int qi = 0; qi < AQ; qi++) {\n                int q = actQ[qi];\n                int mn = 1e9, mx = -1e9;\n                for (int pid : candP[k]) {\n                    int c = fields[k].pls[pid].contrib[q];\n                    mn = min(mn, c);\n                    mx = max(mx, c);\n                }\n                fMinQ[pos][qi] = (unsigned short)mn;\n                fMaxQ[pos][qi] = (unsigned short)mx;\n            }\n            for (int t = 0; t < D; t++) {\n                int mn = 1, mx = 0;\n                int idx = drilledCells[t];\n                for (int pid : candP[k]) {\n                    int c = mask_test(fields[k].pls[pid].mask, idx);\n                    mn = min(mn, c);\n                    mx = max(mx, c);\n                }\n                fMinD[pos][t] = (unsigned char)mn;\n                fMaxD[pos][t] = (unsigned char)mx;\n            }\n        }\n\n        vector<vector<unsigned short>> remMinQ(M + 1, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned short>> remMaxQ(M + 1, vector<unsigned short>(AQ, 0));\n        vector<vector<unsigned char>> remMinD(M + 1, vector<unsigned char>(D, 0));\n        vector<vector<unsigned char>> remMaxD(M + 1, vector<unsigned char>(D, 0));\n\n        for (int pos = M - 1; pos >= 0; pos--) {\n            for (int qi = 0; qi < AQ; qi++) {\n                remMinQ[pos][qi] = remMinQ[pos + 1][qi] + fMinQ[pos][qi];\n                remMaxQ[pos][qi] = remMaxQ[pos + 1][qi] + fMaxQ[pos][qi];\n            }\n            for (int t = 0; t < D; t++) {\n                remMinD[pos][t] = remMinD[pos + 1][t] + fMinD[pos][t];\n                remMaxD[pos][t] = remMaxD[pos + 1][t] + fMaxD[pos][t];\n            }\n        }\n\n        int TA = totalArea;\n        vector<vector<double>> rangeMin(AQ, vector<double>((TA + 1) * (TA + 1), 1e100));\n        for (int qi = 0; qi < AQ; qi++) {\n            int q = actQ[qi];\n            for (int l = 0; l <= TA; l++) {\n                double mn = 1e100;\n                for (int r = l; r <= TA; r++) {\n                    mn = min(mn, qScore[q][r]);\n                    rangeMin[qi][l * (TA + 1) + r] = mn;\n                }\n            }\n        }\n\n        struct BNode {\n            int penLB = 0;\n            double divLB = 0.0;\n            array<short, MAXQ> qsum{};\n            array<unsigned char, MAXD_BEAM> dsum{};\n            array<unsigned short, 20> choice{};\n        };\n\n        auto cmpNode = [&](const BNode &a, const BNode &b) {\n            if (a.penLB != b.penLB) return a.penLB < b.penLB;\n            return a.divLB < b.divLB;\n        };\n\n        vector<BNode> beam(1);\n        beam[0].qsum.fill(0);\n        beam[0].dsum.fill(0);\n        beam[0].choice.fill(0);\n\n        for (int pos = 0; pos < M; pos++) {\n            int k = order[pos];\n            vector<BNode> next;\n            next.reserve((int)beam.size() * min(localKeep, (int)candP[k].size()));\n\n            for (const auto &cur : beam) {\n                vector<BNode> local;\n                local.reserve(candP[k].size());\n\n                for (int pid : candP[k]) {\n                    const auto &pl = fields[k].pls[pid];\n                    BNode nd = cur;\n                    nd.choice[pos] = (unsigned short)pid;\n\n                    for (int qi = 0; qi < AQ; qi++) {\n                        nd.qsum[qi] += pl.contrib[actQ[qi]];\n                    }\n                    for (int t = 0; t < D; t++) {\n                        nd.dsum[t] += (unsigned char)mask_test(pl.mask, drilledCells[t]);\n                    }\n\n                    int penlb = 0;\n                    for (int t = 0; t < D; t++) {\n                        int L = nd.dsum[t] + remMinD[pos + 1][t];\n                        int R = nd.dsum[t] + remMaxD[pos + 1][t];\n                        int obs = drilledObs[t];\n                        if (obs < L) {\n                            int d = L - obs;\n                            penlb += d * d;\n                        } else if (obs > R) {\n                            int d = obs - R;\n                            penlb += d * d;\n                        }\n                    }\n\n                    double divlb = 0.0;\n                    for (int qi = 0; qi < AQ; qi++) {\n                        int L = nd.qsum[qi] + remMinQ[pos + 1][qi];\n                        int R = nd.qsum[qi] + remMaxQ[pos + 1][qi];\n                        if (L < 0) L = 0;\n                        if (R > TA) R = TA;\n                        if (L > R) swap(L, R);\n                        divlb += rangeMin[qi][L * (TA + 1) + R];\n                    }\n\n                    nd.penLB = penlb;\n                    nd.divLB = divlb;\n                    local.push_back(move(nd));\n                }\n\n                if ((int)local.size() > localKeep) {\n                    partial_sort(local.begin(), local.begin() + localKeep, local.end(), cmpNode);\n                    local.resize(localKeep);\n                }\n                for (auto &x : local) next.push_back(move(x));\n            }\n\n            if (next.empty()) return false;\n            if ((int)next.size() > beamWidth) {\n                partial_sort(next.begin(), next.begin() + beamWidth, next.end(), cmpNode);\n                next.resize(beamWidth);\n            } else {\n                sort(next.begin(), next.end(), cmpNode);\n            }\n            beam.swap(next);\n\n            if (elapsed() > 2.58) break;\n        }\n\n        vector<State> exactStates;\n        int takeFinal = min(12, (int)beam.size());\n        for (int i = 0; i < takeFinal; i++) {\n            vector<int> choice(M);\n            for (int pos = 0; pos < M; pos++) choice[order[pos]] = beam[i].choice[pos];\n            exactStates.push_back(build_state(choice));\n        }\n\n        exactBeamRuns++;\n        return merge_states(move(exactStates));\n    }\n\n    bool full_beam_merge_if_worth(int stage) {\n        if (M > 9) return false;\n        if (elapsed() > 2.35) return false;\n\n        auto us = summarize_unions();\n        auto ws = collect_weighted_states();\n        if (ws.idx.empty()) return false;\n\n        bool worth = false;\n        if (stage == 1) {\n            worth = (us.distinctUnionCount >= 5 || us.bestWeight < 0.72 || ws.bestPen > 0);\n        } else if (stage == 2) {\n            worth = (us.distinctUnionCount >= 3 || us.bestWeight < 0.90 || ws.bestPen > 0);\n        } else {\n            worth = (us.distinctUnionCount >= 2 || us.bestWeight < 0.95 || ws.bestPen > 0);\n        }\n        if (!worth) return false;\n\n        vector<vector<int>> candP(M);\n        double candLog = 0.0;\n        for (int k = 0; k < M; k++) {\n            for (int pid = 0; pid < (int)fields[k].pls.size(); pid++) {\n                if (zero_compatible(k, pid)) candP[k].push_back(pid);\n            }\n            if (candP[k].empty()) return false;\n            candLog += log2((double)candP[k].size());\n        }\n\n        if ((M <= 6 && candLog > 82.0) ||\n            (M == 7 && candLog > 72.0) ||\n            (M == 8 && candLog > 64.0) ||\n            (M == 9 && candLog > 58.0)) return false;\n\n        int beamWidth = (M <= 5 ? 1600 : M <= 6 ? 1200 : M <= 7 ? 800 : 500);\n        int localKeep = (M <= 6 ? 24 : 16);\n        if (candLog > 68.0) beamWidth = max(300, beamWidth / 2);\n\n        return beam_merge_from_candidates(candP, beamWidth, localKeep);\n    }\n\n    bool restricted_beam_merge_if_worth() {\n        if (M > 14) return false;\n        if (pool.empty()) return false;\n        if (elapsed() > 2.42) return false;\n\n        auto us = summarize_unions();\n        auto ws = collect_weighted_states();\n        if (ws.idx.empty()) return false;\n\n        if (!(us.distinctUnionCount >= 3 || us.bestWeight < 0.86 || ws.bestPen > 0)) return false;\n\n        const State &base = pool[ws.idx[0]];\n        int topUse = min(10, (int)ws.idx.size());\n        int maxPerField = (M <= 8 ? 6 : 5);\n\n        vector<vector<int>> candP(M);\n        double candLog = 0.0;\n\n        for (int k = 0; k < M; k++) {\n            int P = (int)fields[k].pls.size();\n            vector<double> score(P, -1.0);\n            for (int pid = 0; pid < P; pid++) {\n                if (zero_compatible(k, pid)) score[pid] = 0.0;\n            }\n\n            for (int t = 0; t < topUse; t++) {\n                int si = ws.idx[t];\n                int pid = pool[si].choice[k];\n                if (score[pid] >= 0.0) score[pid] += ws.w[t] / ws.sumW;\n            }\n\n            vector<int> ids;\n            ids.reserve(P);\n            for (int pid = 0; pid < P; pid++) if (score[pid] >= 0.0) ids.push_back(pid);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (score[a] != score[b]) return score[a] > score[b];\n                if (a == base.choice[k]) return true;\n                if (b == base.choice[k]) return false;\n                return a < b;\n            });\n\n            vector<char> used(P, 0);\n            for (int pid : ids) {\n                if ((int)candP[k].size() >= min(4, maxPerField)) break;\n                if (score[pid] <= 0.0 && !candP[k].empty()) break;\n                candP[k].push_back(pid);\n                used[pid] = 1;\n            }\n\n            if (!used[base.choice[k]] && zero_compatible(k, base.choice[k])) {\n                candP[k].push_back(base.choice[k]);\n                used[base.choice[k]] = 1;\n            }\n\n            auto alts = best_alternatives_from_base(base, k, used, maxPerField - (int)candP[k].size());\n            for (int pid : alts) {\n                candP[k].push_back(pid);\n                used[pid] = 1;\n            }\n\n            if (candP[k].empty()) return false;\n            while ((int)candP[k].size() > maxPerField) candP[k].pop_back();\n\n            candLog += log2((double)candP[k].size());\n        }\n\n        if (candLog > 52.0) return false;\n\n        int beamWidth = (M <= 8 ? 900 : M <= 11 ? 650 : 450);\n        int localKeep = (M <= 8 ? 20 : 12);\n\n        return beam_merge_from_candidates(candP, beamWidth, localKeep);\n    }\n\n    // ---------- drill bookkeeping ----------\n    void record_drill(int idx, int val) {\n        if (!drilledFlag[idx]) {\n            drilledFlag[idx] = 1;\n            cellObs[idx] = val;\n            drilledCells.push_back(idx);\n            drilledObs.push_back(val);\n        }\n    }\n\n    // ---------- summaries ----------\n    Mask union_of_choice(const vector<int> &choice) {\n        Mask u{};\n        mask_clear(u);\n        for (int k = 0; k < M; k++) mask_or_eq(u, fields[k].pls[choice[k]].mask);\n        return u;\n    }\n\n    vector<unsigned char> state_counts(const State &st) {\n        vector<unsigned char> cnt(NN, 0);\n        for (int k = 0; k < M; k++) {\n            const auto &pl = fields[k].pls[st.choice[k]];\n            for (auto [ri, rj] : fields[k].rel) {\n                int idx = (pl.di + ri) * N + (pl.dj + rj);\n                cnt[idx]++;\n            }\n        }\n        return cnt;\n    }\n\n    WeightedStates collect_weighted_states() {\n        WeightedStates ws;\n        if (pool.empty()) return ws;\n\n        vector<char> usable(pool.size(), 0);\n        for (int i = 0; i < (int)pool.size(); i++) {\n            Mask u = union_of_choice(pool[i].choice);\n            if (is_rejected_mask(u)) continue;\n            usable[i] = 1;\n            ws.bestPen = min(ws.bestPen, pool[i].pen);\n        }\n        if (ws.bestPen == INT_MAX) return ws;\n\n        int aq = max(1, activeQCount());\n\n        if (ws.bestPen == 0) {\n            double bestDiv = 1e100;\n            for (int i = 0; i < (int)pool.size(); i++) {\n                if (!usable[i]) continue;\n                if (pool[i].pen == 0) bestDiv = min(bestDiv, pool[i].div);\n            }\n\n            double margin = 8.0 + 0.30 * aq;\n            for (int i = 0; i < (int)pool.size(); i++) {\n                if (!usable[i]) continue;\n                if (pool[i].pen != 0) continue;\n                if (pool[i].div <= bestDiv + margin) {\n                    double w = exp(-min(50.0, (pool[i].div - bestDiv) / 2.5));\n                    ws.idx.push_back(i);\n                    ws.w.push_back(w);\n                    ws.sumW += w;\n                }\n            }\n            ws.plausible = !ws.idx.empty();\n        }\n\n        if (!ws.plausible) {\n            vector<int> ids;\n            for (int i = 0; i < (int)pool.size(); i++) if (usable[i]) ids.push_back(i);\n            int take = min(14, (int)ids.size());\n\n            double base = 1e100;\n            vector<double> obj(take);\n            for (int t = 0; t < take; t++) {\n                int i = ids[t];\n                obj[t] = pool[i].div + 20.0 * pool[i].pen;\n                base = min(base, obj[t]);\n            }\n            for (int t = 0; t < take; t++) {\n                int i = ids[t];\n                double w = exp(-min(50.0, (obj[t] - base) / 4.0));\n                ws.idx.push_back(i);\n                ws.w.push_back(w);\n                ws.sumW += w;\n            }\n        }\n\n        if (ws.sumW <= 0.0) {\n            ws.sumW = (double)ws.w.size();\n            for (double &x : ws.w) x = 1.0;\n        }\n        return ws;\n    }\n\n    void compute_cell_stats(const WeightedStates &ws,\n                            vector<double> &supportProb,\n                            vector<double> &supportVar,\n                            vector<double> &countVar) {\n        supportProb.assign(NN, 0.0);\n        supportVar.assign(NN, 0.0);\n        countVar.assign(NN, 0.0);\n        if (ws.idx.empty()) return;\n\n        vector<double> meanCnt(NN, 0.0), sqCnt(NN, 0.0);\n\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            const State &st = pool[ws.idx[t]];\n            double w = ws.w[t];\n            vector<unsigned char> cnt = state_counts(st);\n\n            for (int idx = 0; idx < NN; idx++) {\n                double c = cnt[idx];\n                if (c > 0) supportProb[idx] += w;\n                meanCnt[idx] += w * c;\n                sqCnt[idx] += w * c * c;\n            }\n        }\n\n        for (int idx = 0; idx < NN; idx++) {\n            supportProb[idx] /= ws.sumW;\n            double p = supportProb[idx];\n            supportVar[idx] = p * (1.0 - p);\n\n            meanCnt[idx] /= ws.sumW;\n            sqCnt[idx] /= ws.sumW;\n            countVar[idx] = max(0.0, sqCnt[idx] - meanCnt[idx] * meanCnt[idx]);\n        }\n    }\n\n    UnionSummary summarize_unions() {\n        UnionSummary us;\n        if (pool.empty()) return us;\n\n        WeightedStates ws = collect_weighted_states();\n        us.hasPlausible = ws.plausible;\n        us.bestPen = ws.bestPen;\n        if (ws.idx.empty()) return us;\n\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            Mask u = union_of_choice(pool[ws.idx[t]].choice);\n            double w = ws.w[t];\n            int pos = -1;\n            for (int i = 0; i < (int)us.masks.size(); i++) {\n                if (us.masks[i] == u) {\n                    pos = i;\n                    break;\n                }\n            }\n            if (pos == -1) {\n                us.masks.push_back(u);\n                us.weights.push_back(w);\n            } else {\n                us.weights[pos] += w;\n            }\n        }\n\n        us.distinctUnionCount = (int)us.masks.size();\n        if (us.masks.empty()) return us;\n\n        double sumW = 0.0;\n        for (double w : us.weights) sumW += w;\n        if (sumW <= 0.0) {\n            sumW = (double)us.weights.size();\n            for (double &w : us.weights) w = 1.0;\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)us.weights.size(); i++) {\n            if (us.weights[i] > us.weights[bestIdx]) bestIdx = i;\n        }\n        us.bestMask = us.masks[bestIdx];\n        us.bestWeight = us.weights[bestIdx] / sumW;\n\n        if (us.hasPlausible) {\n            us.must1 = us.masks[0];\n            us.maybe1 = us.masks[0];\n            for (int i = 1; i < (int)us.masks.size(); i++) {\n                mask_and_eq(us.must1, us.masks[i]);\n                mask_or_eq(us.maybe1, us.masks[i]);\n            }\n            Mask amb = mask_xor(us.must1, us.maybe1);\n            for (int idx = 0; idx < NN; idx++) if (mask_test(amb, idx)) us.ambiguous.push_back(idx);\n        }\n\n        compute_cell_stats(ws, us.supportProb, us.supportVar, us.countVar);\n\n        us.maxCellScore = -1.0;\n        us.bestCell = -1;\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            for (int idx : us.ambiguous) {\n                if (drilledFlag[idx]) continue;\n                double sc = us.supportVar[idx] + 0.15 * min(1.0, us.countVar[idx]);\n                if (sc > us.maxCellScore + 1e-15) {\n                    us.maxCellScore = sc;\n                    us.bestCell = idx;\n                }\n            }\n        }\n\n        if (us.bestCell == -1) {\n            for (int idx = 0; idx < NN; idx++) {\n                if (drilledFlag[idx]) continue;\n                double sc = 0.8 * us.supportVar[idx] + 0.2 * min(1.0, us.countVar[idx]);\n                if (sc > us.maxCellScore + 1e-15) {\n                    us.maxCellScore = sc;\n                    us.bestCell = idx;\n                }\n            }\n        }\n\n        return us;\n    }\n\n    // ---------- answering / fallback ----------\n    Mask consensus_answer_mask(const UnionSummary &us) {\n        Mask ans = us.must1;\n        for (int idx = 0; idx < NN; idx++) if (cellObs[idx] > 0) mask_set(ans, idx);\n        return ans;\n    }\n\n    bool try_answer_strong(double weightThreshold, bool allowLowVar) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (is_rejected_mask(us.bestMask)) return false;\n\n        bool ok = false;\n        if (us.distinctUnionCount == 1) ok = true;\n        else if (us.bestWeight >= weightThreshold) ok = true;\n        else if (allowLowVar && us.bestWeight >= 0.90 && us.maxCellScore >= 0.0 && us.maxCellScore < 0.01) ok = true;\n\n        if (!ok) return false;\n        if (!can_spend_ops(1)) return false;\n        return submit_guess(us.bestMask);\n    }\n\n    bool try_dual_guess(double minBestWeight, int minNeedForTwoGuesses) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (us.distinctUnionCount != 2) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n\n        if (!(us.bestWeight >= minBestWeight || need >= minNeedForTwoGuesses)) return false;\n        if (!can_spend_ops(2)) return false;\n\n        vector<int> ord = {0, 1};\n        if (us.weights[1] > us.weights[0]) swap(ord[0], ord[1]);\n\n        for (int id : ord) {\n            if (is_rejected_mask(us.masks[id])) continue;\n            if (submit_guess(us.masks[id])) return true;\n        }\n        return false;\n    }\n\n    bool try_one_last_best_guess() {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (is_rejected_mask(us.bestMask)) return false;\n        if (!can_spend_ops(1)) return false;\n        return submit_guess(us.bestMask);\n    }\n\n    void full_drill_and_answer() {\n        for (int idx = 0; idx < NN; idx++) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n        Mask ans{};\n        mask_clear(ans);\n        for (int idx = 0; idx < NN; idx++) if (cellObs[idx] > 0) mask_set(ans, idx);\n        answer_mask_raw(ans);\n    }\n\n    bool try_small_ambiguous_finish(int limitUndrilled) {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (collect_weighted_states().bestPen != 0) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n\n        if (need == 0) {\n            if (!us.ambiguous.empty()) return false;\n            if (!can_spend_ops(1)) return false;\n            Mask ans = consensus_answer_mask(us);\n            return submit_guess(ans);\n        }\n\n        if (need > limitUndrilled) return false;\n        if (ops + need + 1 > maxOps) return false;\n\n        for (int idx : us.ambiguous) {\n            if (!drilledFlag[idx]) {\n                int v = ask_drill(idx);\n                record_drill(idx, v);\n            }\n        }\n\n        if (elapsed() < 2.45) optimize_pool(4, 10, 4, false);\n        if (elapsed() < 2.35) restricted_beam_merge_if_worth();\n        if (elapsed() < 2.25) full_beam_merge_if_worth(3);\n\n        auto us2 = summarize_unions();\n        if (!us2.hasPlausible) return false;\n        if (collect_weighted_states().bestPen != 0) return false;\n        if (!us2.ambiguous.empty()) {\n            if (try_dual_guess(0.85, 6)) return true;\n            return false;\n        }\n\n        if (!can_spend_ops(1)) return false;\n        Mask ans = consensus_answer_mask(us2);\n        return submit_guess(ans);\n    }\n\n    bool speculative_guess() {\n        auto us = summarize_unions();\n        if (!us.hasPlausible) return false;\n        if (collect_weighted_states().bestPen != 0) return false;\n        if (is_rejected_mask(us.bestMask)) return false;\n\n        int need = 0;\n        for (int idx : us.ambiguous) if (!drilledFlag[idx]) need++;\n\n        bool go = false;\n        if (us.bestWeight >= 0.90) go = true;\n        if (us.distinctUnionCount <= 2 && need <= 10) go = true;\n        if (!go) return false;\n        if (!can_spend_ops(1)) return false;\n\n        return submit_guess(us.bestMask);\n    }\n\n    // ---------- adaptive discriminative queries ----------\n    int predicted_sum_on_mask(const State &st, const Mask &m) {\n        int s = 0;\n        for (int k = 0; k < M; k++) s += intersect_count(fields[k].pls[st.choice[k]].mask, m);\n        return s;\n    }\n\n    double evaluate_candidate_query(const Mask &m, const WeightedStates &ws) {\n        int k = mask_popcount(m);\n        if (k < 2 || ws.idx.empty()) return -1e100;\n\n        double mean = 0.0, sq = 0.0;\n        int mn = INT_MAX, mx = INT_MIN;\n        for (int t = 0; t < (int)ws.idx.size(); t++) {\n            int pred = predicted_sum_on_mask(pool[ws.idx[t]], m);\n            mn = min(mn, pred);\n            mx = max(mx, pred);\n            double w = ws.w[t] / ws.sumW;\n            mean += w * pred;\n            sq += w * pred * pred;\n        }\n        if (mx == mn) return -1e100;\n\n        double varState = max(0.0, sq - mean * mean);\n        double noise = k * eps * (1.0 - eps) + 0.25;\n        return (varState / (noise + 1e-9)) * sqrt((double)k);\n    }\n\n    void add_candidate_mask(vector<Mask> &cand, const Mask &m) {\n        int k = mask_popcount(m);\n        if (k < 2) return;\n        for (const auto &x : cand) if (x == m) return;\n        for (int q = 0; q < Qcur; q++) if (queryMasks[q] == m) return;\n        cand.push_back(m);\n    }\n\n    vector<Mask> generate_candidate_masks(const UnionSummary &us, const WeightedStates &ws) {\n        vector<Mask> cand;\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            Mask amb = mask_xor(us.must1, us.maybe1);\n            add_candidate_mask(cand, amb);\n\n            add_candidate_mask(cand, mask_and(amb, rowParityMask[0]));\n            add_candidate_mask(cand, mask_and(amb, rowParityMask[1]));\n            add_candidate_mask(cand, mask_and(amb, colParityMask[0]));\n            add_candidate_mask(cand, mask_and(amb, colParityMask[1]));\n            add_candidate_mask(cand, mask_and(amb, checkerMask[0]));\n            add_candidate_mask(cand, mask_and(amb, checkerMask[1]));\n\n            if (mask_popcount(amb) >= 10) {\n                for (int r = 0; r < 3; r++) add_candidate_mask(cand, mask_and(amb, rowMod3Mask[r]));\n                for (int c = 0; c < 3; c++) add_candidate_mask(cand, mask_and(amb, colMod3Mask[c]));\n            }\n\n            vector<pair<int,int>> rows, cols;\n            for (int i = 0; i < N; i++) {\n                int cnt = 0;\n                for (int idx : queryCells[i]) cnt += mask_test(amb, idx);\n                if (cnt >= 2) rows.push_back({cnt, i});\n            }\n            for (int j = 0; j < N; j++) {\n                int cnt = 0;\n                for (int idx : queryCells[N + j]) cnt += mask_test(amb, idx);\n                if (cnt >= 2) cols.push_back({cnt, j});\n            }\n            sort(rows.rbegin(), rows.rend());\n            sort(cols.rbegin(), cols.rend());\n            for (int t = 0; t < min(4, (int)rows.size()); t++) add_candidate_mask(cand, mask_and(amb, queryMasks[rows[t].second]));\n            for (int t = 0; t < min(4, (int)cols.size()); t++) add_candidate_mask(cand, mask_and(amb, queryMasks[N + cols[t].second]));\n        }\n\n        if (us.masks.size() >= 2) {\n            int b1 = 0, b2 = -1;\n            for (int i = 1; i < (int)us.weights.size(); i++) {\n                if (us.weights[i] > us.weights[b1]) {\n                    b2 = b1;\n                    b1 = i;\n                } else if (b2 == -1 || us.weights[i] > us.weights[b2]) {\n                    b2 = i;\n                }\n            }\n            if (b2 != -1) {\n                add_candidate_mask(cand, mask_xor(us.masks[b1], us.masks[b2]));\n                add_candidate_mask(cand, mask_andnot(us.masks[b1], us.masks[b2]));\n                add_candidate_mask(cand, mask_andnot(us.masks[b2], us.masks[b1]));\n            }\n        }\n\n        vector<int> ord;\n        ord.reserve(NN);\n        for (int idx = 0; idx < NN; idx++) if (!drilledFlag[idx]) ord.push_back(idx);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (us.supportVar[a] != us.supportVar[b]) return us.supportVar[a] > us.supportVar[b];\n            return us.countVar[a] > us.countVar[b];\n        });\n\n        int take = min((int)ord.size(), max(12, min(64, 2 * N + 12)));\n        Mask topU{};\n        mask_clear(topU);\n        for (int i = 0; i < take; i++) mask_set(topU, ord[i]);\n        add_candidate_mask(cand, topU);\n        add_candidate_mask(cand, mask_and(topU, checkerMask[0]));\n        add_candidate_mask(cand, mask_and(topU, checkerMask[1]));\n        add_candidate_mask(cand, mask_and(topU, rowParityMask[0]));\n        add_candidate_mask(cand, mask_and(topU, rowParityMask[1]));\n\n        for (int rep = 0; rep < 6; rep++) {\n            Mask h{};\n            mask_clear(h);\n            ull a = rng() | 1ULL;\n            ull b = rng() | 1ULL;\n            ull c = rng();\n            for (int i = 0; i < take; i++) {\n                int idx = ord[i];\n                ull z = a * (ull)(idx + 1) + b * (ull)((idx / N) + 131 * (idx % N) + 7) + c;\n                if ((z >> 63) & 1ULL) mask_set(h, idx);\n            }\n            add_candidate_mask(cand, h);\n            add_candidate_mask(cand, mask_andnot(topU, h));\n        }\n\n        if (us.hasPlausible && !us.ambiguous.empty()) {\n            for (int rep = 0; rep < 6; rep++) {\n                Mask h{};\n                mask_clear(h);\n                ull a = (rng() % 7) * 2 + 1;\n                ull b = (rng() % 7) * 2 + 1;\n                ull c = rng() & 3;\n                for (int idx : us.ambiguous) {\n                    int i = idx / N, j = idx % N;\n                    if ((((a * (ull)i + b * (ull)j + c) & 3ULL) < 2ULL)) mask_set(h, idx);\n                }\n                add_candidate_mask(cand, h);\n            }\n        }\n\n        vector<int> rank(ws.idx.size());\n        iota(rank.begin(), rank.end(), 0);\n        sort(rank.begin(), rank.end(), [&](int a, int b) { return ws.w[a] > ws.w[b]; });\n        int T = min(6, (int)rank.size());\n\n        vector<vector<unsigned char>> cnts;\n        for (int t = 0; t < T; t++) cnts.push_back(state_counts(pool[ws.idx[rank[t]]]));\n\n        for (int a = 0; a < T; a++) {\n            for (int b = a + 1; b < T; b++) {\n                Mask gt{}, lt{}, sdiff{}, bigdiff{};\n                mask_clear(gt); mask_clear(lt); mask_clear(sdiff); mask_clear(bigdiff);\n                for (int idx = 0; idx < NN; idx++) {\n                    int ca = cnts[a][idx];\n                    int cb = cnts[b][idx];\n                    if (ca > cb) mask_set(gt, idx);\n                    if (ca < cb) mask_set(lt, idx);\n                    if ((ca > 0) != (cb > 0)) mask_set(sdiff, idx);\n                    if (abs(ca - cb) >= 2) mask_set(bigdiff, idx);\n                }\n                add_candidate_mask(cand, gt);\n                add_candidate_mask(cand, lt);\n                add_candidate_mask(cand, sdiff);\n                add_candidate_mask(cand, bigdiff);\n                add_candidate_mask(cand, mask_and(gt, checkerMask[0]));\n                add_candidate_mask(cand, mask_and(gt, checkerMask[1]));\n                add_candidate_mask(cand, mask_and(lt, checkerMask[0]));\n                add_candidate_mask(cand, mask_and(lt, checkerMask[1]));\n            }\n        }\n\n        return cand;\n    }\n\n    bool do_adaptive_query_round(int maxQueries, bool canAnswerAfter) {\n        for (int rep = 0; rep < maxQueries; rep++) {\n            if (Qcur >= MAXQ || elapsed() > 2.55) break;\n            if (!can_spend_ops(1)) break;\n\n            auto us = summarize_unions();\n            WeightedStates ws = collect_weighted_states();\n            if (ws.idx.empty()) break;\n\n            vector<Mask> cand = generate_candidate_masks(us, ws);\n            if (cand.empty()) break;\n\n            double bestScore = -1e100;\n            int bestId = -1;\n            for (int i = 0; i < (int)cand.size(); i++) {\n                double sc = evaluate_candidate_query(cand[i], ws);\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    bestId = i;\n                }\n            }\n\n            double threshold = 0.12;\n            if (adaptiveQueriesUsed == 0) threshold = 0.30;\n            else if (adaptiveQueriesUsed < 4) threshold = 0.18;\n\n            if (bestId == -1 || bestScore < threshold) break;\n            if (!add_adaptive_query(cand[bestId])) break;\n\n            optimize_pool(4, 8, 3, false);\n            if (!pool.empty() && collect_weighted_states().bestPen > 0 && elapsed() < 2.25) {\n                optimize_pool(5, 10, 4, false);\n            }\n\n            if (canAnswerAfter) {\n                if (try_answer_strong(0.992, false)) return true;\n                if (try_small_ambiguous_finish(12)) return true;\n            }\n        }\n        return false;\n    }\n\n    bool adaptive_refine_loop(int rounds, bool canAnswerAfter) {\n        for (int t = 0; t < rounds; t++) {\n            if (elapsed() > 2.60) break;\n            int before = adaptiveQueriesUsed;\n            if (do_adaptive_query_round(1, canAnswerAfter)) return true;\n            if (adaptiveQueriesUsed == before) break;\n\n            auto us = summarize_unions();\n            if (us.hasPlausible) {\n                if (try_answer_strong(0.997, true)) return true;\n                if (us.bestWeight > 0.985 && us.maxCellScore < 0.02) {\n                    if (try_answer_strong(0.98, true)) return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    // ---------- main ----------\n    void solve() {\n        stTime = chrono::steady_clock::now();\n\n        read_input();\n        build_queries();\n        precompute_placements();\n\n        bool hard = (M >= 9 || compLog2 > 78.0 || eps >= 0.14);\n\n        // Stage 1: rows + cols\n        activate_queries(0, 2 * N);\n        optimize_pool(14, 0, 6, true);\n\n        if (try_answer_strong(0.999, false)) return;\n        if (try_small_ambiguous_finish(10)) return;\n        if (full_beam_merge_if_worth(1)) {\n            if (try_answer_strong(0.998, false)) return;\n            if (try_small_ambiguous_finish(10)) return;\n        }\n        if (adaptive_refine_loop(hard ? 6 : 4, true)) return;\n\n        // Stage 2: mod2\n        activate_queries(2 * N, 2 * N + 4);\n        optimize_pool(8, 8, 5, false);\n\n        if (restricted_beam_merge_if_worth()) {\n            if (try_answer_strong(0.997, false)) return;\n            if (try_small_ambiguous_finish(12)) return;\n        }\n        if (full_beam_merge_if_worth(2)) {\n            if (try_answer_strong(0.997, false)) return;\n            if (try_small_ambiguous_finish(12)) return;\n        }\n        if (try_answer_strong(0.997, false)) return;\n        if (try_small_ambiguous_finish(12)) return;\n        if (adaptive_refine_loop(hard ? 6 : 4, true)) return;\n\n        // Stage 3: mod3 almost always worth asking\n        auto us = summarize_unions();\n        bool doMod3 = true;\n        if (hard && adaptiveQueriesUsed >= 10 && us.bestWeight < 0.12) doMod3 = false;\n\n        if (doMod3) {\n            activate_queries(2 * N + 4, 2 * N + 13);\n            optimize_pool(8, 10, 5, false);\n\n            if (restricted_beam_merge_if_worth()) {\n                if (try_answer_strong(0.994, false)) return;\n                if (try_small_ambiguous_finish(16)) return;\n            }\n            if (full_beam_merge_if_worth(3)) {\n                if (try_answer_strong(0.994, false)) return;\n                if (try_small_ambiguous_finish(16)) return;\n            }\n            if (try_answer_strong(0.992, false)) return;\n            if (try_small_ambiguous_finish(16)) return;\n            if (try_dual_guess(0.88, 10)) return;\n            if (adaptive_refine_loop(hard ? 5 : 4, true)) return;\n        }\n\n        int heuristicLimit;\n        if (hard) heuristicLimit = 7;\n        else if (M <= 4) heuristicLimit = 18;\n        else if (M <= 8) heuristicLimit = 12;\n        else heuristicLimit = 9;\n\n        for (int step = 0; step < heuristicLimit; step++) {\n            if (elapsed() > 2.62) break;\n\n            auto cur = summarize_unions();\n\n            double wth = 0.97;\n            if ((int)drilledCells.size() >= 2) wth = 0.95;\n            if ((int)drilledCells.size() >= 4) wth = 0.92;\n\n            if (try_answer_strong(wth, true)) return;\n            if (step >= 2 && try_dual_guess(0.90, 10)) return;\n\n            int ambLimit = min(26, 8 + 2 * step);\n            if (try_small_ambiguous_finish(ambLimit)) return;\n\n            if (adaptiveQueriesUsed < 18 && elapsed() < 2.48) {\n                int before = adaptiveQueriesUsed;\n                if (adaptive_refine_loop(step < 2 ? 2 : 1, true)) return;\n                cur = summarize_unions();\n                if (adaptiveQueriesUsed > before) {\n                    if (try_answer_strong(wth, true)) return;\n                    if (try_small_ambiguous_finish(ambLimit)) return;\n                }\n            }\n\n            if (step <= 2 && elapsed() < 2.35) {\n                bool imp = restricted_beam_merge_if_worth();\n                if (!imp && M <= 9) imp = full_beam_merge_if_worth(3);\n                if (imp) {\n                    if (try_answer_strong(wth, true)) return;\n                    if (try_small_ambiguous_finish(ambLimit)) return;\n                    cur = summarize_unions();\n                }\n            }\n\n            int idx = cur.bestCell;\n            if (idx < 0) break;\n            if (ops + 2 > maxOps) break;\n\n            int val = ask_drill(idx);\n            record_drill(idx, val);\n\n            if (elapsed() < 2.5) {\n                optimize_pool(5, 10, 4, false);\n                if (!pool.empty() && collect_weighted_states().bestPen > 0 && elapsed() < 2.25) {\n                    optimize_pool(6, 12, 5, false);\n                }\n            }\n        }\n\n        // Last cheap attempts\n        if (adaptiveQueriesUsed < 22 && elapsed() < 2.55) {\n            if (adaptive_refine_loop(2, true)) return;\n        }\n        if (elapsed() < 2.48) {\n            if (restricted_beam_merge_if_worth()) {\n                if (try_answer_strong(0.92, true)) return;\n            }\n        }\n        if (try_dual_guess(0.80, 8)) return;\n        if (try_small_ambiguous_finish(24)) return;\n        if (try_answer_strong(0.90, true)) return;\n        if (speculative_guess()) return;\n        if (try_one_last_best_guess()) return;\n\n        full_drill_and_answer();\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int W = 1000;\nstatic constexpr long long INF64 = (1LL << 60);\n\nstruct Rect {\n    int i0, j0, i1, j1;\n};\n\nstruct Solution {\n    long long cost = INF64;\n    vector<vector<Rect>> rects; // [D][N]\n};\n\nstruct CutList {\n    int len = 0;\n    int v[50];\n};\n\nstruct DayRowLayout {\n    short l = 0, r = 0;      // [l, r)\n    unsigned char rev = 0;   // 0: forward, 1: reverse\n    short slack_idx = 0;     // which reservation absorbs row slack\n    CutList cuts;\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 D, N;\nvector<vector<int>> a;\n\n// prefW[h][d][k] flattened = sum_{t<k} ceil(a[d][t] / h)\nvector<int> prefW;\nint strideK, strideD;\n\ninline int pref_idx(int h, int d, int k) {\n    return h * strideD + d * strideK + k;\n}\ninline int sum_widths(int h, int d, int l, int r) {\n    return prefW[pref_idx(h, d, r)] - prefW[pref_idx(h, d, l)];\n}\ninline int cell_width(int h, int d, int k) {\n    return prefW[pref_idx(h, d, k + 1)] - prefW[pref_idx(h, d, k)];\n}\n\ninline int count_common_arr(const int* A, int nA, const int* B, int nB) {\n    int i = 0, j = 0, c = 0;\n    while (i < nA && j < nB) {\n        if (A[i] == B[j]) {\n            ++c; ++i; ++j;\n        } else if (A[i] < B[j]) {\n            ++i;\n        } else {\n            ++j;\n        }\n    }\n    return c;\n}\ninline long long dist_cut_arr(const CutList& A, const int* B, int lenB, int h) {\n    int common = count_common_arr(A.v, A.len, B, lenB);\n    return 1LL * h * (A.len + lenB - 2LL * common);\n}\n\ninline bool valid_pattern(const vector<int>& hs) {\n    if (hs.empty()) return false;\n    if ((int)hs.size() > N) return false;\n    int sum = 0;\n    for (int h : hs) {\n        if (h <= 0) return false;\n        sum += h;\n    }\n    return sum <= W;\n}\n\n// ---------- Exact evaluator ----------\n\nlong long evaluate_exact(const vector<vector<Rect>>& rects) {\n    const int HS = (W - 1) * W;\n    const int VS = W * (W - 1);\n    const int HWORDS = (HS + 63) >> 6;\n    const int VWORDS = (VS + 63) >> 6;\n\n    vector<uint64_t> prevH(HWORDS, 0), prevV(VWORDS, 0);\n    vector<uint64_t> curH(HWORDS, 0), curV(VWORDS, 0);\n\n    auto setbit = [](vector<uint64_t>& bits, int idx) {\n        bits[idx >> 6] |= (1ULL << (idx & 63));\n    };\n\n    long long cost = 0;\n\n    for (int d = 0; d < D; ++d) {\n        fill(curH.begin(), curH.end(), 0);\n        fill(curV.begin(), curV.end(), 0);\n\n        for (int k = 0; k < N; ++k) {\n            const auto& r = rects[d][k];\n            long long area = 1LL * (r.i1 - r.i0) * (r.j1 - r.j0);\n            if (area < a[d][k]) cost += 100LL * (a[d][k] - area);\n\n            if (r.i0 > 0) {\n                int base = (r.i0 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.i1 < W) {\n                int base = (r.i1 - 1) * W;\n                for (int j = r.j0; j < r.j1; ++j) setbit(curH, base + j);\n            }\n            if (r.j0 > 0) {\n                int x = r.j0 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n            if (r.j1 < W) {\n                int x = r.j1 - 1;\n                for (int i = r.i0; i < r.i1; ++i) setbit(curV, i * (W - 1) + x);\n            }\n        }\n\n        if (d > 0) {\n            for (int i = 0; i < HWORDS; ++i) cost += __builtin_popcountll(prevH[i] ^ curH[i]);\n            for (int i = 0; i < VWORDS; ++i) cost += __builtin_popcountll(prevV[i] ^ curV[i]);\n        }\n\n        prevH.swap(curH);\n        prevV.swap(curV);\n    }\n\n    return cost;\n}\n\n// ---------- Candidate 1: fixed full-width strips ----------\n\nlong long marginal_gain_all_days(int idx, int cur_h) {\n    long long gain = 0;\n    int area = W * cur_h;\n    for (int d = 0; d < D; ++d) {\n        int rem = a[d][idx] - area;\n        if (rem > 0) gain += 100LL * min(W, rem);\n    }\n    return gain;\n}\n\nvector<int> optimize_fixed_strips_all_days() {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>;\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_all_days(i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_all_days(idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_fixed_strips() {\n    Solution sol;\n    vector<int> h = optimize_fixed_strips_all_days();\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Candidate 2: day-by-day strips ----------\n\nlong long marginal_gain_one_day(int d, int idx, int cur_h) {\n    int area = W * cur_h;\n    int rem = a[d][idx] - area;\n    if (rem <= 0) return 0;\n    return 100LL * min(W, rem);\n}\n\nvector<int> optimize_strips_one_day(int d) {\n    vector<int> h(N, 1);\n    int rem = W - N;\n\n    using Node = tuple<long long, int, int>;\n    priority_queue<Node> pq;\n    for (int i = 0; i < N; ++i) pq.emplace(marginal_gain_one_day(d, i, h[i]), i, h[i]);\n\n    while (rem > 0) {\n        auto [g, idx, ch] = pq.top();\n        pq.pop();\n        if (h[idx] != ch) continue;\n        if (g == 0) {\n            h[N - 1] += rem;\n            break;\n        }\n        ++h[idx];\n        --rem;\n        pq.emplace(marginal_gain_one_day(d, idx, h[idx]), idx, h[idx]);\n    }\n\n    sort(h.begin(), h.end());\n    return h;\n}\n\nSolution solve_daily_strips() {\n    Solution sol;\n    sol.rects.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; ++d) {\n        vector<int> h = optimize_strips_one_day(d);\n        int y = 0;\n        for (int k = 0; k < N; ++k) {\n            sol.rects[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Pattern generation helpers ----------\n\nvector<int> solve_reqH_dp(const vector<vector<int>>& reqH) {\n    vector<int> dpH(N + 1, W + 1), dpRows(N + 1, (int)1e9), parent(N + 1, -1);\n    dpH[0] = 0;\n    dpRows[0] = 0;\n\n    for (int r = 1; r <= N; ++r) {\n        for (int l = 0; l < r; ++l) {\n            int h = reqH[l][r];\n            if (h > W || dpH[l] > W) continue;\n            int nh = dpH[l] + h;\n            int nr = dpRows[l] + 1;\n            if (nh < dpH[r] || (nh == dpH[r] && nr < dpRows[r])) {\n                dpH[r] = nh;\n                dpRows[r] = nr;\n                parent[r] = l;\n            }\n        }\n    }\n\n    if (dpH[N] > W) return {};\n\n    vector<int> hs;\n    int cur = N;\n    while (cur > 0) {\n        int l = parent[cur];\n        hs.push_back(reqH[l][cur]);\n        cur = l;\n    }\n    reverse(hs.begin(), hs.end());\n    return hs;\n}\n\nvector<int> compute_global_pattern_all_days() {\n    auto interval_ok = [&](int l, int r, int h) -> bool {\n        for (int d = 0; d < D; ++d) {\n            if (sum_widths(h, d, l, r) > W) return false;\n        }\n        return true;\n    };\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            if (!interval_ok(l, r, W)) continue;\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (interval_ok(l, r, mid)) hi = mid;\n                else lo = mid + 1;\n            }\n            reqH[l][r] = lo;\n        }\n    }\n    return solve_reqH_dp(reqH);\n}\n\nvector<int> compute_pattern_from_values(vector<int> vec) {\n    for (int k = 1; k < N; ++k) vec[k] = max(vec[k], vec[k - 1]);\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    for (int l = 0; l < N; ++l) {\n        for (int r = l + 1; r <= N; ++r) {\n            long long needW = 0;\n            for (int k = l; k < r; ++k) needW += (vec[k] + W - 1) / W;\n            if (needW > W) continue;\n\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                long long need = 0;\n                for (int k = l; k < r; ++k) need += (vec[k] + mid - 1) / mid;\n                if (need <= W) hi = mid;\n                else lo = mid + 1;\n            }\n            reqH[l][r] = lo;\n        }\n    }\n    return solve_reqH_dp(reqH);\n}\n\nvector<int> quantile_vector(double q) {\n    vector<int> v(N);\n    vector<int> tmp(D);\n    for (int k = 0; k < N; ++k) {\n        for (int d = 0; d < D; ++d) tmp[d] = a[d][k];\n        sort(tmp.begin(), tmp.end());\n        int idx = min(D - 1, max(0, (int)floor(q * (D - 1) + 1e-9)));\n        v[k] = tmp[idx];\n    }\n    for (int k = 1; k < N; ++k) v[k] = max(v[k], v[k - 1]);\n    return v;\n}\n\nvector<int> scaled_max_vector() {\n    vector<int> mx(N, 0);\n    for (int k = 0; k < N; ++k) {\n        for (int d = 0; d < D; ++d) mx[k] = max(mx[k], a[d][k]);\n    }\n    for (int k = 1; k < N; ++k) mx[k] = max(mx[k], mx[k - 1]);\n\n    long long sum = 0;\n    for (int x : mx) sum += x;\n    if (sum <= 1000000LL) return mx;\n\n    double scale = 1000000.0 / (double)sum;\n    vector<int> v(N);\n    for (int k = 0; k < N; ++k) v[k] = max(1, (int)floor(mx[k] * scale));\n    for (int k = 1; k < N; ++k) v[k] = max(v[k], v[k - 1]);\n    return v;\n}\n\nvector<int> make_equal_heights(int R) {\n    vector<int> hs(R, W / R);\n    int rem = W % R;\n    for (int i = 0; i < rem; ++i) hs[R - 1 - i]++;\n    return hs;\n}\n\nvector<int> stretch_pattern_proportional_to_target(const vector<int>& hs, int target) {\n    if (hs.empty()) return {};\n    int S = 0;\n    for (int x : hs) S += x;\n    if (S <= 0 || S > W) return {};\n    target = max(S, min(W, target));\n    if (target == S) return hs;\n\n    int m = (int)hs.size();\n    vector<int> out(m);\n    vector<pair<double, int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; ++i) {\n        double raw = (double)hs[i] * target / (double)S;\n        int v = max(1, (int)floor(raw));\n        out[i] = v;\n        used += v;\n        frac.push_back({raw - v, i});\n    }\n    sort(frac.begin(), frac.end(), [&](auto& a, auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    int p = 0;\n    while (used < target) {\n        out[frac[p].second]++;\n        ++used;\n        ++p;\n        if (p == m) p = 0;\n    }\n    while (used > target) {\n        bool ok = false;\n        for (int i = m - 1; i >= 0; --i) {\n            int id = frac[i].second;\n            if (out[id] > 1) {\n                out[id]--;\n                --used;\n                ok = true;\n                if (used == target) break;\n            }\n        }\n        if (!ok) break;\n    }\n    return out;\n}\n\nvector<int> stretch_pattern_proportional(const vector<int>& hs) {\n    return stretch_pattern_proportional_to_target(hs, W);\n}\n\nvector<int> stretch_pattern_proportional_partial(const vector<int>& hs, int num, int den) {\n    if (hs.empty()) return {};\n    int S = 0;\n    for (int x : hs) S += x;\n    if (S <= 0 || S > W) return {};\n    int target = S + (int)((1LL * (W - S) * num + den / 2) / den);\n    return stretch_pattern_proportional_to_target(hs, target);\n}\n\nvector<int> stretch_pattern_tail(const vector<int>& hs) {\n    if (hs.empty()) return {};\n    vector<int> out = hs;\n    int S = 0;\n    for (int x : out) S += x;\n    if (S <= 0 || S > W) return {};\n    if (S < W) out.back() += (W - S);\n    return out;\n}\n\nvector<int> stretch_pattern_index_weighted(const vector<int>& hs) {\n    if (hs.empty()) return {};\n    vector<int> out = hs;\n    int S = 0;\n    for (int x : out) S += x;\n    if (S <= 0 || S > W) return {};\n    int rem = W - S;\n    if (rem <= 0) return out;\n\n    int m = (int)out.size();\n    long long wsum = 1LL * m * (m + 1) / 2;\n    vector<pair<double, int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; ++i) {\n        double raw = (double)rem * (i + 1) / (double)wsum;\n        int add = (int)floor(raw);\n        out[i] += add;\n        used += add;\n        frac.push_back({raw - add, i});\n    }\n    sort(frac.begin(), frac.end(), [&](auto& a, auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second > b.second;\n    });\n    int p = 0;\n    while (used < rem) {\n        out[frac[p].second]++;\n        ++used;\n        ++p;\n        if (p == m) p = 0;\n    }\n    return out;\n}\n\nvector<vector<int>> generate_adjacent_transfer_neighbors(const vector<int>& hs) {\n    vector<vector<int>> res;\n    int m = (int)hs.size();\n    if (m <= 1) return res;\n    for (int i = 0; i + 1 < m; ++i) {\n        int pairSum = hs[i] + hs[i + 1];\n        int d1 = max(1, min(32, pairSum / 4));\n        int d2 = max(1, min(12, pairSum / 8));\n        int ds[2] = {d1, d2};\n        for (int ti = 0; ti < 2; ++ti) {\n            int d = ds[ti];\n            if (ti == 1 && d == ds[0]) continue;\n            if (hs[i + 1] - d >= 1) {\n                auto t = hs;\n                t[i] += d;\n                t[i + 1] -= d;\n                res.push_back(std::move(t));\n            }\n            if (hs[i] - d >= 1) {\n                auto t = hs;\n                t[i] -= d;\n                t[i + 1] += d;\n                res.push_back(std::move(t));\n            }\n        }\n    }\n    return res;\n}\n\nvector<vector<int>> generate_swap_neighbors(const vector<int>& hs) {\n    vector<vector<int>> res;\n    int m = (int)hs.size();\n    for (int i = 0; i + 1 < m; ++i) {\n        if (hs[i] == hs[i + 1]) continue;\n        auto t = hs;\n        swap(t[i], t[i + 1]);\n        res.push_back(std::move(t));\n    }\n    vector<int> rev = hs;\n    reverse(rev.begin(), rev.end());\n    if (rev != hs) res.push_back(std::move(rev));\n    return res;\n}\n\nvector<vector<int>> generate_split_merge_neighbors(const vector<int>& hs) {\n    vector<vector<int>> res;\n    int m = (int)hs.size();\n\n    // Merge adjacent rows\n    if (m >= 2) {\n        for (int i = 0; i + 1 < m; ++i) {\n            auto t = hs;\n            t[i] += t[i + 1];\n            t.erase(t.begin() + i + 1);\n            res.push_back(std::move(t));\n        }\n    }\n\n    // Split one row into two\n    if (m < N) {\n        for (int i = 0; i < m; ++i) {\n            int h = hs[i];\n            vector<pair<int,int>> splits;\n\n            auto addSplit = [&](int a, int b) {\n                if (a >= 1 && b >= 1 && a + b == h) splits.push_back({a, b});\n            };\n\n            addSplit(h / 2, h - h / 2);\n            addSplit(h - h / 2, h / 2);\n            if (h >= 3) {\n                addSplit(1, h - 1);\n                addSplit(h - 1, 1);\n            }\n            if (h >= 6) {\n                addSplit(2, h - 2);\n                addSplit(h - 2, 2);\n            }\n\n            sort(splits.begin(), splits.end());\n            splits.erase(unique(splits.begin(), splits.end()), splits.end());\n\n            for (auto [a, b] : splits) {\n                auto t = hs;\n                t[i] = a;\n                t.insert(t.begin() + i + 1, b);\n                res.push_back(std::move(t));\n            }\n        }\n    }\n\n    return res;\n}\n\n// ---------- Candidate 3: fixed intervals across all days ----------\n\nstruct RowChoice {\n    int l, r;\n    int h;\n    int last_idx;\n    bool rev;\n};\n\nstruct RowDPResult {\n    Solution sol;\n    vector<int> heights;\n    bool feasible = false;\n};\n\nRowDPResult solve_row_dp_zero_shortage_fixed_intervals(const Timer& timer, double limit_sec) {\n    RowDPResult res;\n    res.sol.cost = INF64;\n\n    auto interval_ok = [&](int l, int r, int h) -> bool {\n        for (int d = 0; d < D; ++d) {\n            if (sum_widths(h, d, l, r) > W) return false;\n        }\n        return true;\n    };\n\n    vector<vector<int>> reqH(N + 1, vector<int>(N + 1, W + 1));\n    vector<vector<long long>> rowCost(N + 1, vector<long long>(N + 1, INF64));\n    vector<vector<int>> bestLast(N + 1, vector<int>(N + 1, -1));\n    vector<vector<char>> bestRev(N + 1, vector<char>(N + 1, 0));\n\n    for (int l = 0; l < N; ++l) {\n        if (timer.elapsed() > limit_sec - 0.80) return res;\n        for (int r = l + 1; r <= N; ++r) {\n            if (!interval_ok(l, r, W)) continue;\n\n            int lo = 1, hi = W;\n            while (lo < hi) {\n                int mid = (lo + hi) >> 1;\n                if (interval_ok(l, r, mid)) hi = mid;\n                else lo = mid + 1;\n            }\n            int h = lo;\n            reqH[l][r] = h;\n\n            int m = r - l;\n            if (m == 1) {\n                rowCost[l][r] = 0;\n                bestLast[l][r] = l;\n                bestRev[l][r] = 0;\n                continue;\n            }\n\n            long long bestC = INF64;\n            int bestP = l;\n            bool bestR = false;\n\n            int prevCuts[55], curCuts[55];\n            for (int p = l; p < r; ++p) {\n                for (int rev = 0; rev <= 1; ++rev) {\n                    long long total = 0;\n                    int prevLen = 0;\n\n                    for (int d = 0; d < D; ++d) {\n                        int len = 0, s = 0;\n                        if (!rev) {\n                            for (int k = l; k < r; ++k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        } else {\n                            for (int k = r - 1; k >= l; --k) if (k != p) {\n                                s += cell_width(h, d, k);\n                                curCuts[len++] = s;\n                            }\n                        }\n\n                        if (d > 0) {\n                            int common = count_common_arr(prevCuts, prevLen, curCuts, len);\n                            total += 2LL * h * (len - common);\n                        }\n                        prevLen = len;\n                        for (int i = 0; i < len; ++i) prevCuts[i] = curCuts[i];\n                    }\n\n                    if (total < bestC) {\n                        bestC = total;\n                        bestP = p;\n                        bestR = (bool)rev;\n                    }\n                }\n            }\n\n            rowCost[l][r] = bestC;\n            bestLast[l][r] = bestP;\n            bestRev[l][r] = (char)bestR;\n        }\n    }\n\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, INF64));\n    vector<vector<short>> prvI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> prvH(N + 1, vector<short>(W + 1, -1));\n    dp[0][0] = 0;\n\n    for (int i = 0; i < N; ++i) {\n        if (timer.elapsed() > limit_sec - 0.60) return res;\n        for (int used = 0; used <= W; ++used) {\n            if (dp[i][used] >= INF64) continue;\n            for (int j = i + 1; j <= N; ++j) {\n                int h = reqH[i][j];\n                if (h > W || used + h > W) continue;\n                long long nd = dp[i][used] + rowCost[i][j];\n                if (nd < dp[j][used + h]) {\n                    dp[j][used + h] = nd;\n                    prvI[j][used + h] = (short)i;\n                    prvH[j][used + h] = (short)used;\n                }\n            }\n        }\n    }\n\n    int bestUsed = -1;\n    long long bestVal = INF64;\n    for (int used = 0; used <= W; ++used) {\n        if (dp[N][used] < bestVal) {\n            bestVal = dp[N][used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0 || bestVal >= INF64) return res;\n\n    vector<RowChoice> rows;\n    {\n        int ci = N, ch = bestUsed;\n        while (ci > 0) {\n            int pi = prvI[ci][ch];\n            int ph = prvH[ci][ch];\n            RowChoice rc;\n            rc.l = pi;\n            rc.r = ci;\n            rc.h = reqH[pi][ci];\n            rc.last_idx = bestLast[pi][ci];\n            rc.rev = bestRev[pi][ci];\n            rows.push_back(rc);\n            ci = pi;\n            ch = ph;\n        }\n        reverse(rows.begin(), rows.end());\n    }\n\n    res.heights.clear();\n    for (auto& rc : rows) res.heights.push_back(rc.h);\n\n    res.sol.rects.assign(D, vector<Rect>(N));\n    int y = 0;\n    for (const auto& row : rows) {\n        int l = row.l, r = row.r, h = row.h, p = row.last_idx;\n        bool rev = row.rev;\n\n        for (int d = 0; d < D; ++d) {\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r; ++k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            } else {\n                for (int k = r - 1; k >= l; --k) if (k != p) {\n                    int w = cell_width(h, d, k);\n                    res.sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            }\n            res.sol.rects[d][p] = {y, x, y + h, W};\n        }\n        y += h;\n    }\n\n    if (timer.elapsed() > limit_sec - 0.30) return res;\n\n    res.sol.cost = evaluate_exact(res.sol.rects);\n    res.feasible = true;\n    return res;\n}\n\n// ---------- Candidate 4: fixed row heights, variable daily intervals ----------\n\nstatic long long intervalCost[55][55][55];\nstatic unsigned char intervalRev[55][55][55];\nstatic short intervalSlack[55][55][55];\nstatic long long dpDay[55][55];\nstatic short parL[55][55];\nstatic unsigned char parRev[55][55];\nstatic short parSlack[55][55];\n\ninline void build_cuts_with_slack(int h, int d, int l, int r, bool rev, int slack_idx, CutList& out) {\n    int slack = W - sum_widths(h, d, l, r);\n    out.len = max(0, r - l - 1);\n\n    int x = 0, p = 0;\n    if (!rev) {\n        for (int k = l; k < r - 1; ++k) {\n            x += cell_width(h, d, k);\n            if (k == slack_idx) x += slack;\n            out.v[p++] = x;\n        }\n    } else {\n        for (int k = r - 1; k > l; --k) {\n            x += cell_width(h, d, k);\n            if (k == slack_idx) x += slack;\n            out.v[p++] = x;\n        }\n    }\n}\n\nbool optimize_one_day_for_pattern(\n    int d,\n    const vector<int>& hs,\n    const vector<DayRowLayout>* prevDay,\n    const vector<DayRowLayout>* nextDay,\n    bool useProxy,\n    bool richSlack,\n    vector<DayRowLayout>& out\n) {\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return false;\n\n    int cuts[50];\n\n    for (int row = 0; row < R; ++row) {\n        int h = hs[row];\n        const CutList* pc = prevDay ? &((*prevDay)[row].cuts) : nullptr;\n        const CutList* nc = nextDay ? &((*nextDay)[row].cuts) : nullptr;\n\n        for (int l = 0; l <= N; ++l) {\n            for (int r = 0; r <= N; ++r) {\n                intervalCost[row][l][r] = INF64;\n                intervalRev[row][l][r] = 0;\n                intervalSlack[row][l][r] = 0;\n            }\n        }\n\n        for (int l = 0; l < N; ++l) {\n            for (int r = l + 1; r <= N; ++r) {\n                int minW = sum_widths(h, d, l, r);\n                if (minW > W) continue;\n                int len = r - l - 1;\n                int m = r - l;\n\n                if (!pc && !nc && useProxy) {\n                    intervalCost[row][l][r] = 1LL * h * len;\n                    intervalRev[row][l][r] = 0;\n                    intervalSlack[row][l][r] = (short)(r - 1);\n                    continue;\n                }\n\n                vector<int> candPos;\n                candPos.reserve(10);\n                auto addCand = [&](int x) {\n                    if (x < l || x >= r) return;\n                    for (int y : candPos) if (y == x) return;\n                    candPos.push_back(x);\n                };\n\n                if (!richSlack) {\n                    addCand(l);\n                    addCand(r - 1);\n                } else {\n                    if (m <= 8) {\n                        for (int k = l; k < r; ++k) addCand(k);\n                    } else {\n                        addCand(l);\n                        addCand(l + 1);\n                        addCand((2 * l + r - 1) / 3);\n                        addCand((l + 2 * (r - 1)) / 3);\n                        addCand(r - 2);\n                        addCand(r - 1);\n                    }\n                }\n\n                for (int rev = 0; rev <= 1; ++rev) {\n                    if (!richSlack) {\n                        int slack_idx = (rev ? l : r - 1);\n                        int x = 0, p = 0;\n                        if (!rev) {\n                            for (int k = l; k < r - 1; ++k) {\n                                x += cell_width(h, d, k);\n                                cuts[p++] = x;\n                            }\n                        } else {\n                            for (int k = r - 1; k > l; --k) {\n                                x += cell_width(h, d, k);\n                                cuts[p++] = x;\n                            }\n                        }\n\n                        long long c = 0;\n                        if (pc) c += dist_cut_arr(*pc, cuts, len, h);\n                        if (nc) c += dist_cut_arr(*nc, cuts, len, h);\n\n                        if (c < intervalCost[row][l][r]) {\n                            intervalCost[row][l][r] = c;\n                            intervalRev[row][l][r] = (unsigned char)rev;\n                            intervalSlack[row][l][r] = (short)slack_idx;\n                        }\n                    } else {\n                        for (int slack_idx : candPos) {\n                            int slack = W - minW;\n                            int x = 0, p = 0;\n\n                            if (!rev) {\n                                for (int k = l; k < r - 1; ++k) {\n                                    x += cell_width(h, d, k);\n                                    if (k == slack_idx) x += slack;\n                                    cuts[p++] = x;\n                                }\n                            } else {\n                                for (int k = r - 1; k > l; --k) {\n                                    x += cell_width(h, d, k);\n                                    if (k == slack_idx) x += slack;\n                                    cuts[p++] = x;\n                                }\n                            }\n\n                            long long c = 0;\n                            if (pc) c += dist_cut_arr(*pc, cuts, len, h);\n                            if (nc) c += dist_cut_arr(*nc, cuts, len, h);\n\n                            if (c < intervalCost[row][l][r]) {\n                                intervalCost[row][l][r] = c;\n                                intervalRev[row][l][r] = (unsigned char)rev;\n                                intervalSlack[row][l][r] = (short)slack_idx;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    for (int i = 0; i <= R; ++i) {\n        for (int j = 0; j <= N; ++j) {\n            dpDay[i][j] = INF64;\n            parL[i][j] = -1;\n            parRev[i][j] = 0;\n            parSlack[i][j] = 0;\n        }\n    }\n    dpDay[0][0] = 0;\n\n    for (int row = 0; row < R; ++row) {\n        for (int l = 0; l <= N; ++l) {\n            if (dpDay[row][l] >= INF64) continue;\n            int minR = l + 1;\n            int maxR = N - (R - row - 1);\n            for (int r = minR; r <= maxR; ++r) {\n                long long c = intervalCost[row][l][r];\n                if (c >= INF64) continue;\n                long long nd = dpDay[row][l] + c;\n                if (nd < dpDay[row + 1][r]) {\n                    dpDay[row + 1][r] = nd;\n                    parL[row + 1][r] = (short)l;\n                    parRev[row + 1][r] = intervalRev[row][l][r];\n                    parSlack[row + 1][r] = intervalSlack[row][l][r];\n                }\n            }\n        }\n    }\n\n    if (dpDay[R][N] >= INF64) return false;\n\n    out.assign(R, DayRowLayout{});\n    int cur = N;\n    for (int row = R; row >= 1; --row) {\n        int l = parL[row][cur];\n        bool rev = parRev[row][cur];\n        int slack_idx = parSlack[row][cur];\n\n        out[row - 1].l = (short)l;\n        out[row - 1].r = (short)cur;\n        out[row - 1].rev = (unsigned char)rev;\n        out[row - 1].slack_idx = (short)slack_idx;\n        build_cuts_with_slack(hs[row - 1], d, l, cur, rev, slack_idx, out[row - 1].cuts);\n        cur = l;\n    }\n\n    return true;\n}\n\nSolution solve_fixed_height_pattern(\n    const vector<int>& hs,\n    const Timer& timer,\n    double limit_sec,\n    int extra_sweeps,\n    bool richSlack\n) {\n    Solution sol;\n    int R = (int)hs.size();\n    if (R <= 0 || R > N) return sol;\n\n    int sumH = 0;\n    for (int h : hs) {\n        if (h <= 0) return sol;\n        sumH += h;\n    }\n    if (sumH > W) return sol;\n\n    vector<vector<DayRowLayout>> lay(D, vector<DayRowLayout>(R));\n\n    if (timer.elapsed() > limit_sec - 0.25) return sol;\n\n    if (!optimize_one_day_for_pattern(0, hs, nullptr, nullptr, true, richSlack, lay[0])) return sol;\n    for (int d = 1; d < D; ++d) {\n        if (timer.elapsed() > limit_sec - 0.25) return sol;\n        if (!optimize_one_day_for_pattern(d, hs, &lay[d - 1], nullptr, false, richSlack, lay[d])) return sol;\n    }\n\n    for (int d = D - 2; d >= 0; --d) {\n        if (timer.elapsed() > limit_sec - 0.25) return sol;\n        const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n        if (!optimize_one_day_for_pattern(d, hs, prevDay, &lay[d + 1], false, richSlack, lay[d])) return sol;\n    }\n\n    for (int it = 0; it < extra_sweeps; ++it) {\n        if (timer.elapsed() > limit_sec - 0.50) break;\n        for (int d = 0; d < D; ++d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, richSlack, lay[d])) return sol;\n        }\n        for (int d = D - 1; d >= 0; --d) {\n            const vector<DayRowLayout>* prevDay = (d > 0 ? &lay[d - 1] : nullptr);\n            const vector<DayRowLayout>* nextDay = (d + 1 < D ? &lay[d + 1] : nullptr);\n            if (!optimize_one_day_for_pattern(d, hs, prevDay, nextDay, false, richSlack, lay[d])) return sol;\n        }\n    }\n\n    if (timer.elapsed() > limit_sec - 0.18) return sol;\n\n    sol.rects.assign(D, vector<Rect>(N));\n    vector<int> y0(R + 1, 0);\n    for (int r = 0; r < R; ++r) y0[r + 1] = y0[r] + hs[r];\n\n    for (int d = 0; d < D; ++d) {\n        for (int row = 0; row < R; ++row) {\n            int y = y0[row];\n            int h = hs[row];\n            int l = lay[d][row].l;\n            int r = lay[d][row].r;\n            bool rev = lay[d][row].rev;\n            int slack_idx = lay[d][row].slack_idx;\n            int slack = W - sum_widths(h, d, l, r);\n\n            int x = 0;\n            if (!rev) {\n                for (int k = l; k < r; ++k) {\n                    int w = cell_width(h, d, k);\n                    if (k == slack_idx) w += slack;\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            } else {\n                for (int k = r - 1; k >= l; --k) {\n                    int w = cell_width(h, d, k);\n                    if (k == slack_idx) w += slack;\n                    sol.rects[d][k] = {y, x, y + h, x + w};\n                    x += w;\n                }\n            }\n        }\n    }\n\n    sol.cost = evaluate_exact(sol.rects);\n    return sol;\n}\n\n// ---------- Utility ----------\n\nvoid consider_best(Solution& best, Solution&& cand) {\n    if (cand.cost < best.cost) best = std::move(cand);\n}\n\n// ---------- Main ----------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double LIMIT_SEC = 2.80;\n    const double PHASE1_END = 1.92;\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    strideK = N + 1;\n    strideD = D * strideK;\n    prefW.assign((W + 1) * strideD, 0);\n\n    for (int h = 1; h <= W; ++h) {\n        for (int d = 0; d < D; ++d) {\n            prefW[pref_idx(h, d, 0)] = 0;\n            for (int k = 0; k < N; ++k) {\n                prefW[pref_idx(h, d, k + 1)] =\n                    prefW[pref_idx(h, d, k)] + (a[d][k] + h - 1) / h;\n            }\n        }\n    }\n\n    Solution best = solve_fixed_strips();\n    if (timer.elapsed() < LIMIT_SEC - 1.00) {\n        consider_best(best, solve_daily_strips());\n    }\n\n    RowDPResult rowdp = solve_row_dp_zero_shortage_fixed_intervals(timer, LIMIT_SEC);\n    if (rowdp.feasible) consider_best(best, std::move(rowdp.sol));\n\n    vector<vector<int>> patterns;\n    set<vector<int>> seen;\n\n    auto add_pattern_raw = [&](const vector<int>& hs) {\n        if (!valid_pattern(hs)) return;\n        if (seen.insert(hs).second) patterns.push_back(hs);\n    };\n\n    auto add_pattern = [&](vector<int> hs, bool add_sorted_variant = false) {\n        add_pattern_raw(hs);\n        if (add_sorted_variant) {\n            vector<int> t = hs;\n            sort(t.begin(), t.end());\n            add_pattern_raw(t);\n        }\n    };\n\n    if (rowdp.feasible) {\n        add_pattern(rowdp.heights, true);\n        add_pattern(stretch_pattern_proportional_partial(rowdp.heights, 1, 2), true);\n        add_pattern(stretch_pattern_proportional_partial(rowdp.heights, 3, 4), true);\n        add_pattern(stretch_pattern_proportional(rowdp.heights), true);\n        add_pattern(stretch_pattern_tail(rowdp.heights), true);\n        add_pattern(stretch_pattern_index_weighted(rowdp.heights), true);\n    }\n\n    if (timer.elapsed() < LIMIT_SEC - 1.35) {\n        auto globalPattern = compute_global_pattern_all_days();\n        add_pattern(globalPattern, true);\n        add_pattern(stretch_pattern_proportional_partial(globalPattern, 1, 2), true);\n        add_pattern(stretch_pattern_proportional_partial(globalPattern, 3, 4), true);\n        add_pattern(stretch_pattern_proportional(globalPattern), true);\n        add_pattern(stretch_pattern_tail(globalPattern), true);\n        add_pattern(stretch_pattern_index_weighted(globalPattern), true);\n    }\n\n    if (timer.elapsed() < LIMIT_SEC - 1.15) {\n        int bestDay = 0;\n        long long bestSum = -1;\n        for (int d = 0; d < D; ++d) {\n            long long s = 0;\n            for (int k = 0; k < N; ++k) s += a[d][k];\n            if (s > bestSum) {\n                bestSum = s;\n                bestDay = d;\n            }\n        }\n\n        auto bestDayPattern = compute_pattern_from_values(a[bestDay]);\n        add_pattern(bestDayPattern, true);\n        add_pattern(stretch_pattern_proportional(bestDayPattern), true);\n\n        vector<int> avgVec(N, 0);\n        for (int k = 0; k < N; ++k) {\n            long long s = 0;\n            for (int d = 0; d < D; ++d) s += a[d][k];\n            avgVec[k] = (int)((s + D / 2) / D);\n        }\n        add_pattern(compute_pattern_from_values(avgVec), true);\n\n        add_pattern(compute_pattern_from_values(quantile_vector(0.75)), true);\n        add_pattern(compute_pattern_from_values(quantile_vector(0.90)), false);\n        add_pattern(compute_pattern_from_values(scaled_max_vector()), true);\n    }\n\n    for (int R : {4, 5, 6, 3, 8, 2, 10, 1}) {\n        if (R <= N) add_pattern(make_equal_heights(R), false);\n    }\n\n    map<vector<int>, long long> quickMemo;\n\n    auto eval_quick = [&](const vector<int>& hs, double end_limit, Solution* keepSol = nullptr) -> long long {\n        auto it = quickMemo.find(hs);\n        if (it != quickMemo.end()) return it->second;\n\n        Solution cand = solve_fixed_height_pattern(hs, timer, end_limit, 0, false);\n        if (cand.cost >= INF64) return INF64;\n\n        long long sc = cand.cost;\n        quickMemo.emplace(hs, sc);\n        if (keepSol) *keepSol = cand;\n        consider_best(best, std::move(cand));\n        return sc;\n    };\n\n    vector<pair<long long, int>> phase1_res;\n\n    // Phase 1: quick evaluation of many patterns\n    for (int idx = 0; idx < (int)patterns.size(); ++idx) {\n        if (timer.elapsed() > PHASE1_END - 0.10) break;\n        long long sc = eval_quick(patterns[idx], PHASE1_END);\n        if (sc < INF64) phase1_res.push_back({sc, idx});\n    }\n\n    sort(phase1_res.begin(), phase1_res.end());\n\n    // Phase 2: refine best quick patterns\n    int top_refine = min<int>(4, phase1_res.size());\n    vector<vector<int>> elite_patterns;\n    for (int rank = 0; rank < top_refine; ++rank) {\n        if (timer.elapsed() > LIMIT_SEC - 0.38) break;\n        int idx = phase1_res[rank].second;\n        elite_patterns.push_back(patterns[idx]);\n\n        int sweeps = (rank == 0 && timer.elapsed() < LIMIT_SEC - 1.00) ? 2 : 1;\n\n        Solution cand = solve_fixed_height_pattern(\n            patterns[idx], timer, LIMIT_SEC, sweeps, false\n        );\n        if (cand.cost < INF64) consider_best(best, std::move(cand));\n\n        if (rank < 2 && timer.elapsed() < LIMIT_SEC - 0.95) {\n            Solution richCand = solve_fixed_height_pattern(\n                patterns[idx], timer, LIMIT_SEC, 0, true\n            );\n            if (richCand.cost < INF64) consider_best(best, std::move(richCand));\n        }\n    }\n\n    // Phase 3: hill-climb around best quick patterns\n    if (!phase1_res.empty() && timer.elapsed() < LIMIT_SEC - 0.95) {\n        vector<pair<long long, vector<int>>> hill_res;\n        set<vector<int>> hillSeen;\n\n        int seeds = min<int>(3, phase1_res.size());\n        for (int si = 0; si < seeds; ++si) {\n            if (timer.elapsed() > LIMIT_SEC - 0.62) break;\n\n            vector<int> cur = patterns[phase1_res[si].second];\n            long long curScore = phase1_res[si].first;\n            hillSeen.insert(cur);\n\n            int maxIter = (si == 0 ? 5 : 4);\n            for (int iter = 0; iter < maxIter; ++iter) {\n                if (timer.elapsed() > LIMIT_SEC - 0.62) break;\n\n                vector<vector<int>> neighs = generate_adjacent_transfer_neighbors(cur);\n                auto sw = generate_swap_neighbors(cur);\n                auto sm = generate_split_merge_neighbors(cur);\n                neighs.insert(neighs.end(), sw.begin(), sw.end());\n                neighs.insert(neighs.end(), sm.begin(), sm.end());\n\n                long long bestNScore = curScore;\n                vector<int> bestN;\n\n                for (auto& hs : neighs) {\n                    if (timer.elapsed() > LIMIT_SEC - 0.52) break;\n                    if (!valid_pattern(hs)) continue;\n                    if (!hillSeen.insert(hs).second) continue;\n\n                    long long sc = eval_quick(hs, LIMIT_SEC);\n                    if (sc < bestNScore) {\n                        bestNScore = sc;\n                        bestN = hs;\n                    }\n                }\n\n                if (bestNScore < curScore) {\n                    curScore = bestNScore;\n                    cur = std::move(bestN);\n                } else {\n                    break;\n                }\n            }\n\n            hill_res.push_back({curScore, cur});\n        }\n\n        sort(hill_res.begin(), hill_res.end(),\n             [](const auto& x, const auto& y) { return x.first < y.first; });\n\n        int hill_refine = min<int>(3, hill_res.size());\n        for (int i = 0; i < hill_refine; ++i) {\n            if (timer.elapsed() > LIMIT_SEC - 0.28) break;\n            elite_patterns.push_back(hill_res[i].second);\n\n            int sweeps = (i == 0 && timer.elapsed() < LIMIT_SEC - 1.00) ? 2 : 1;\n            Solution cand = solve_fixed_height_pattern(\n                hill_res[i].second, timer, LIMIT_SEC, sweeps, false\n            );\n            if (cand.cost < INF64) consider_best(best, std::move(cand));\n\n            if (i < 2 && timer.elapsed() < LIMIT_SEC - 0.88) {\n                Solution richCand = solve_fixed_height_pattern(\n                    hill_res[i].second, timer, LIMIT_SEC, 0, true\n                );\n                if (richCand.cost < INF64) consider_best(best, std::move(richCand));\n            }\n        }\n    }\n\n    // Phase 4: final intensification on elite patterns\n    {\n        set<vector<int>> uniq;\n        vector<vector<int>> uniq_elite;\n        for (auto& p : elite_patterns) {\n            if (uniq.insert(p).second) uniq_elite.push_back(p);\n        }\n\n        vector<pair<long long, vector<int>>> elite_scored;\n        for (auto& p : uniq_elite) {\n            auto it = quickMemo.find(p);\n            if (it != quickMemo.end()) elite_scored.push_back({it->second, p});\n        }\n        sort(elite_scored.begin(), elite_scored.end(),\n             [](const auto& x, const auto& y) { return x.first < y.first; });\n\n        int fin = min<int>(2, elite_scored.size());\n        for (int i = 0; i < fin; ++i) {\n            if (timer.elapsed() > LIMIT_SEC - 0.18) break;\n            int sweeps = (i == 0 && timer.elapsed() < LIMIT_SEC - 0.72) ? 4 : 3;\n            Solution cand = solve_fixed_height_pattern(\n                elite_scored[i].second, timer, LIMIT_SEC, sweeps, true\n            );\n            if (cand.cost < INF64) consider_best(best, std::move(cand));\n        }\n    }\n\n    for (int d = 0; d < D; ++d) {\n        for (int k = 0; k < N; ++k) {\n            const auto& r = best.rects[d][k];\n            cout << r.i0 << ' ' << r.j0 << ' ' << r.i1 << ' ' << r.j1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nusing i64 = long long;\nusing u32 = uint32_t;\n\nstatic constexpr u32 MOD = 998244353;\nstatic constexpr int N = 9;\nstatic constexpr int M = 20;\nstatic constexpr int K = 81;\n\nstatic constexpr int REFINE_COMBO_MAX = 5;\n\n// Construction beam\nstatic constexpr int BEAM_WIDTH_PER_USED = 3;\nstatic constexpr int TOP_SINGLE = 2;\nstatic constexpr int TOP_PAIR = 2;\nstatic constexpr int TOP_TRIPLE = 1;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 0) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int next_int(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nstruct Combo {\n    uint8_t cost = 0;\n    uint8_t ids[REFINE_COMBO_MAX]{};\n    u32 add[9]{};\n};\n\nstruct BeamNode {\n    u32 board[81]{};\n    i64 score = 0;\n    uint8_t used = 0;\n    int parent = -1;\n    int combo_id = 0;\n};\n\nstruct Solution {\n    u32 board[81]{};\n    i64 score = 0;\n    int used = 0;\n\n    int pos_cid[49]{};\n    u32 pos_add[49][9]{};\n    uint8_t pos_count[49]{};\n    uint8_t pos_ids[49][REFINE_COMBO_MAX]{};\n};\n\nclass Solver {\npublic:\n    Timer timer;\n    SplitMix64 rng;\n\n    u32 init_board[81]{};\n    i64 init_score = 0;\n    u32 stamp[20][9]{};\n    uint8_t pos_cells[49][9]{};\n\n    vector<Combo> combos;\n    array<vector<int>, REFINE_COMBO_MAX + 1> combo_ids_by_cost;\n    vector<int> all_positions;\n\n    void read_input() {\n        int n, m, k;\n        cin >> n >> m >> k;\n        (void)n; (void)m; (void)k;\n\n        uint64_t seed = 0x123456789abcdef0ULL;\n        auto mix = [&](uint64_t v) {\n            seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        };\n\n        for (int i = 0; i < 81; i++) {\n            cin >> init_board[i];\n            init_score += init_board[i];\n            mix(init_board[i] + 1000003ULL * (i + 1));\n        }\n        for (int m0 = 0; m0 < 20; m0++) {\n            for (int i = 0; i < 3; i++) {\n                for (int j = 0; j < 3; j++) {\n                    cin >> stamp[m0][i * 3 + j];\n                    mix(stamp[m0][i * 3 + j] + 10007ULL * (m0 + 1) + 131ULL * i + j);\n                }\n            }\n        }\n        rng = SplitMix64(seed);\n\n        build_pos_cells();\n        build_combos();\n\n        all_positions.resize(49);\n        iota(all_positions.begin(), all_positions.end(), 0);\n    }\n\n    void solve() {\n        const double TL = 1.94;\n\n        array<int, 49> row_order = make_row_major_order();\n        Solution best = build_by_beam(row_order);\n\n        if (timer.elapsed() < 0.22) {\n            array<int, 49> gain_order = make_gain_order();\n            Solution alt = build_by_beam(gain_order);\n            if (better(alt, best)) best = std::move(alt);\n        }\n\n        // Cheap diversified starts\n        if (timer.elapsed() < 0.20) {\n            for (int t = 0; t < 2 && timer.elapsed() < 0.30; t++) {\n                Solution alt = build_randomized_greedy();\n                refine_positions(alt, all_positions, min(0.55, TL), 1);\n                if (better(alt, best)) best = std::move(alt);\n            }\n        }\n\n        refine_positions(best, all_positions, 0.95, 3);\n\n        while (timer.elapsed() < 1.88) {\n            Solution cur = best;\n            int mode = rng.next_int(100);\n\n            vector<int> removed;\n            if (mode < 40) removed = random_destroy(cur);\n            else if (mode < 75) removed = weak_destroy(cur);\n            else removed = cluster_destroy(cur);\n\n            vector<int> focus = expand_focus_positions(removed);\n            double sub_limit = min(TL - 0.02,\n                                   timer.elapsed() + 0.07 + 0.01 * (int)focus.size() / 10 + (mode >= 75 ? 0.02 : 0.0));\n\n            refine_positions(cur, focus, sub_limit, 2);\n\n            if (timer.elapsed() + 0.015 < sub_limit) {\n                refine_positions(cur, all_positions, sub_limit, 1);\n            }\n\n            if (better(cur, best)) best = std::move(cur);\n        }\n\n        refine_positions(best, all_positions, TL, 5);\n\n        output(best);\n    }\n\nprivate:\n    static inline i64 add_gain_cell(u32 x, u32 s) {\n        return (x + s >= MOD) ? (i64)s - MOD : (i64)s;\n    }\n\n    static inline i64 remove_gain_cell(u32 x, u32 s) {\n        return (x >= s) ? -(i64)s : (i64)MOD - s;\n    }\n\n    inline i64 gain_local(const u32 x[9], const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += add_gain_cell(x[k], add[k]);\n        return g;\n    }\n\n    inline void extract_local(const u32 board[81], int pos, u32 x[9]) const {\n        for (int k = 0; k < 9; k++) x[k] = board[pos_cells[pos][k]];\n    }\n\n    inline i64 gain_add_pos(const u32 board[81], int pos, const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += add_gain_cell(board[pos_cells[pos][k]], add[k]);\n        return g;\n    }\n\n    inline i64 gain_remove_pos(const u32 board[81], int pos, const u32 add[9]) const {\n        i64 g = 0;\n        for (int k = 0; k < 9; k++) g += remove_gain_cell(board[pos_cells[pos][k]], add[k]);\n        return g;\n    }\n\n    inline void apply_add_pos(u32 board[81], int pos, const u32 add[9]) const {\n        for (int k = 0; k < 9; k++) {\n            u32 &v = board[pos_cells[pos][k]];\n            v += add[k];\n            if (v >= MOD) v -= MOD;\n        }\n    }\n\n    inline void apply_remove_pos(u32 board[81], int pos, const u32 add[9]) const {\n        for (int k = 0; k < 9; k++) {\n            u32 &v = board[pos_cells[pos][k]];\n            u32 s = add[k];\n            if (v >= s) v -= s;\n            else v = v + MOD - s;\n        }\n    }\n\n    void build_pos_cells() {\n        for (int p = 0; p < 7; p++) {\n            for (int q = 0; q < 7; q++) {\n                int pos = p * 7 + q;\n                int t = 0;\n                for (int i = 0; i < 3; i++) {\n                    for (int j = 0; j < 3; j++) {\n                        pos_cells[pos][t++] = (uint8_t)((p + i) * 9 + (q + j));\n                    }\n                }\n            }\n        }\n    }\n\n    void build_combos() {\n        combos.clear();\n        for (auto &v : combo_ids_by_cost) v.clear();\n        combos.reserve(60000);\n\n        Combo zero;\n        zero.cost = 0;\n        combos.push_back(zero);\n        combo_ids_by_cost[0].push_back(0);\n\n        u32 cur[9]{};\n        uint8_t ids[REFINE_COMBO_MAX]{};\n\n        function<void(int,int,int)> dfs = [&](int start, int depth, int target) {\n            if (depth == target) {\n                Combo c;\n                c.cost = (uint8_t)target;\n                for (int i = 0; i < target; i++) c.ids[i] = ids[i];\n                for (int k = 0; k < 9; k++) c.add[k] = cur[k];\n                int idx = (int)combos.size();\n                combos.push_back(c);\n                combo_ids_by_cost[target].push_back(idx);\n                return;\n            }\n            for (int m0 = start; m0 < 20; m0++) {\n                ids[depth] = (uint8_t)m0;\n                for (int k = 0; k < 9; k++) {\n                    u32 x = cur[k] + stamp[m0][k];\n                    if (x >= MOD) x -= MOD;\n                    cur[k] = x;\n                }\n                dfs(m0, depth + 1, target);\n                for (int k = 0; k < 9; k++) {\n                    u32 s = stamp[m0][k];\n                    if (cur[k] >= s) cur[k] -= s;\n                    else cur[k] = cur[k] + MOD - s;\n                }\n            }\n        };\n\n        for (int cost = 1; cost <= REFINE_COMBO_MAX; cost++) {\n            dfs(0, 0, cost);\n        }\n    }\n\n    Solution make_empty_solution() const {\n        Solution sol;\n        memcpy(sol.board, init_board, sizeof(init_board));\n        sol.score = init_score;\n        sol.used = 0;\n        for (int pos = 0; pos < 49; pos++) {\n            sol.pos_cid[pos] = 0;\n            sol.pos_count[pos] = 0;\n            for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = 0;\n            for (int t = 0; t < REFINE_COMBO_MAX; t++) sol.pos_ids[pos][t] = 0;\n        }\n        return sol;\n    }\n\n    void set_pos_meta(Solution &sol, int pos, int cid) const {\n        sol.pos_cid[pos] = cid;\n        const Combo &cb = combos[cid];\n        sol.pos_count[pos] = cb.cost;\n        for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = cb.add[k];\n        for (int t = 0; t < REFINE_COMBO_MAX; t++) {\n            sol.pos_ids[pos][t] = (t < cb.cost ? cb.ids[t] : 0);\n        }\n    }\n\n    void clear_pos_meta(Solution &sol, int pos) const {\n        sol.pos_cid[pos] = 0;\n        sol.pos_count[pos] = 0;\n        for (int k = 0; k < 9; k++) sol.pos_add[pos][k] = 0;\n        for (int t = 0; t < REFINE_COMBO_MAX; t++) sol.pos_ids[pos][t] = 0;\n    }\n\n    void remove_position_combo(Solution &sol, int pos) const {\n        int cid = sol.pos_cid[pos];\n        if (cid == 0) return;\n        sol.score += gain_remove_pos(sol.board, pos, combos[cid].add);\n        apply_remove_pos(sol.board, pos, combos[cid].add);\n        sol.used -= combos[cid].cost;\n        clear_pos_meta(sol, pos);\n    }\n\n    bool better(const Solution &a, const Solution &b) const {\n        if (a.score != b.score) return a.score > b.score;\n        return a.used < b.used;\n    }\n\n    template<size_t SZ>\n    static inline void push_top(array<pair<i64,int>, SZ>& best, i64 gain, int cid) {\n        for (size_t i = 0; i < SZ; i++) {\n            if (gain > best[i].first) {\n                for (size_t j = SZ - 1; j > i; j--) best[j] = best[j - 1];\n                best[i] = {gain, cid};\n                return;\n            }\n        }\n    }\n\n    array<int, 49> make_row_major_order() const {\n        array<int, 49> ord{};\n        iota(ord.begin(), ord.end(), 0);\n        return ord;\n    }\n\n    array<int, 49> make_gain_order() const {\n        array<pair<i64,int>, 49> arr{};\n        for (int pos = 0; pos < 49; pos++) {\n            u32 x[9];\n            extract_local(init_board, pos, x);\n            i64 best = 0;\n            for (int c = 1; c <= 3; c++) {\n                for (int cid : combo_ids_by_cost[c]) {\n                    i64 g = gain_local(x, combos[cid].add);\n                    if (g > best) best = g;\n                }\n            }\n            arr[pos] = {best, pos};\n        }\n        sort(arr.begin(), arr.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        array<int, 49> ord{};\n        for (int i = 0; i < 49; i++) ord[i] = arr[i].second;\n        return ord;\n    }\n\n    Solution build_by_beam(const array<int, 49>& order) {\n        vector<vector<BeamNode>> layers(50);\n\n        BeamNode root;\n        memcpy(root.board, init_board, sizeof(init_board));\n        root.score = init_score;\n        root.used = 0;\n        root.parent = -1;\n        root.combo_id = 0;\n        layers[0].push_back(root);\n\n        array<vector<int>, K + 1> bucket_cur, bucket_nxt;\n        bucket_cur[0].push_back(0);\n\n        for (int step = 0; step < 49; step++) {\n            int pos = order[step];\n            array<vector<BeamNode>, K + 1> cand;\n            const auto &cur_layer = layers[step];\n\n            for (int used = 0; used <= K; used++) {\n                for (int idx : bucket_cur[used]) {\n                    const BeamNode &st = cur_layer[idx];\n\n                    u32 x[9];\n                    extract_local(st.board, pos, x);\n\n                    array<pair<i64,int>, TOP_SINGLE> best1;\n                    array<pair<i64,int>, TOP_PAIR> best2;\n                    array<pair<i64,int>, TOP_TRIPLE> best3;\n                    for (auto &p : best1) p = {-(1LL << 60), -1};\n                    for (auto &p : best2) p = {-(1LL << 60), -1};\n                    for (auto &p : best3) p = {-(1LL << 60), -1};\n\n                    if (used + 1 <= K) {\n                        for (int cid : combo_ids_by_cost[1]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best1, g, cid);\n                        }\n                    }\n                    if (used + 2 <= K) {\n                        for (int cid : combo_ids_by_cost[2]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best2, g, cid);\n                        }\n                    }\n                    if (used + 3 <= K) {\n                        for (int cid : combo_ids_by_cost[3]) {\n                            i64 g = gain_local(x, combos[cid].add);\n                            push_top(best3, g, cid);\n                        }\n                    }\n\n                    auto make_child = [&](int cid) {\n                        const Combo &cb = combos[cid];\n                        BeamNode ch;\n                        memcpy(ch.board, st.board, sizeof(st.board));\n                        if (cid != 0) apply_add_pos(ch.board, pos, cb.add);\n                        ch.score = st.score + (cid == 0 ? 0 : gain_local(x, cb.add));\n                        ch.used = (uint8_t)(used + cb.cost);\n                        ch.parent = idx;\n                        ch.combo_id = cid;\n                        cand[ch.used].push_back(std::move(ch));\n                    };\n\n                    make_child(0);\n                    for (auto [g, cid] : best1) if (cid != -1) make_child(cid);\n                    for (auto [g, cid] : best2) if (cid != -1) make_child(cid);\n                    for (auto [g, cid] : best3) if (cid != -1) make_child(cid);\n                }\n            }\n\n            vector<BeamNode> next_layer;\n            for (auto &v : bucket_nxt) v.clear();\n\n            for (int used = 0; used <= K; used++) {\n                auto &vec = cand[used];\n                if (vec.empty()) continue;\n                sort(vec.begin(), vec.end(), [](const BeamNode &a, const BeamNode &b) {\n                    if (a.score != b.score) return a.score > b.score;\n                    return a.used < b.used;\n                });\n                if ((int)vec.size() > BEAM_WIDTH_PER_USED) vec.resize(BEAM_WIDTH_PER_USED);\n                for (auto &node : vec) {\n                    bucket_nxt[used].push_back((int)next_layer.size());\n                    next_layer.push_back(std::move(node));\n                }\n            }\n\n            layers[step + 1] = std::move(next_layer);\n            bucket_cur = std::move(bucket_nxt);\n        }\n\n        int best_idx = 0;\n        i64 best_score = -(1LL << 60);\n        int best_used = 1e9;\n        for (int i = 0; i < (int)layers[49].size(); i++) {\n            if (layers[49][i].score > best_score ||\n                (layers[49][i].score == best_score && layers[49][i].used < best_used)) {\n                best_score = layers[49][i].score;\n                best_used = layers[49][i].used;\n                best_idx = i;\n            }\n        }\n\n        int chosen_combo[49];\n        int cur = best_idx;\n        for (int step = 49; step >= 1; step--) {\n            chosen_combo[step - 1] = layers[step][cur].combo_id;\n            cur = layers[step][cur].parent;\n        }\n\n        Solution sol = make_empty_solution();\n        memcpy(sol.board, layers[49][best_idx].board, sizeof(sol.board));\n        sol.score = layers[49][best_idx].score;\n        sol.used = 0;\n\n        for (int step = 0; step < 49; step++) {\n            int pos = order[step];\n            int cid = chosen_combo[step];\n            set_pos_meta(sol, pos, cid);\n            sol.used += combos[cid].cost;\n        }\n        return sol;\n    }\n\n    Solution build_randomized_greedy() {\n        Solution sol = make_empty_solution();\n\n        vector<int> ord = all_positions;\n        shuffle_positions(ord);\n\n        for (int pos : ord) {\n            int avail = K - sol.used;\n            int maxc = min(3, avail);\n            if (maxc <= 0) break;\n\n            array<pair<i64,int>, 6> best;\n            for (auto &p : best) p = {-(1LL << 60), -1};\n\n            u32 x[9];\n            extract_local(sol.board, pos, x);\n\n            for (int c = 1; c <= maxc; c++) {\n                for (int cid : combo_ids_by_cost[c]) {\n                    i64 g = gain_local(x, combos[cid].add);\n                    push_top(best, g, cid);\n                }\n            }\n\n            vector<pair<i64,int>> cand;\n            for (auto [g, cid] : best) {\n                if (cid != -1 && g > 0) cand.push_back({g, cid});\n            }\n            if (cand.empty()) continue;\n\n            int pick = 0;\n            int r = rng.next_int(100);\n            if ((int)cand.size() >= 2 && r >= 65) pick = 1;\n            if ((int)cand.size() >= 3 && r >= 90) pick = 2;\n\n            int cid = cand[pick].second;\n            sol.score += gain_add_pos(sol.board, pos, combos[cid].add);\n            apply_add_pos(sol.board, pos, combos[cid].add);\n            sol.used += combos[cid].cost;\n            set_pos_meta(sol, pos, cid);\n        }\n\n        return sol;\n    }\n\n    void shuffle_positions(vector<int>& ord) {\n        for (int i = (int)ord.size() - 1; i > 0; i--) {\n            int j = rng.next_int(i + 1);\n            swap(ord[i], ord[j]);\n        }\n    }\n\n    void refine_positions(Solution &sol, const vector<int>& base_positions, double time_limit, int max_rounds) {\n        if (base_positions.empty()) return;\n        vector<int> ord = base_positions;\n\n        for (int round = 0; round < max_rounds && timer.elapsed() < time_limit; round++) {\n            shuffle_positions(ord);\n            bool changed = false;\n\n            for (int pos : ord) {\n                if (timer.elapsed() >= time_limit) return;\n\n                int old_cid = sol.pos_cid[pos];\n                if (old_cid != 0) remove_position_combo(sol, pos);\n\n                u32 x[9];\n                extract_local(sol.board, pos, x);\n\n                int available = K - sol.used;\n                int maxc = min(REFINE_COMBO_MAX, available);\n\n                int best_cid = 0;\n                i64 best_delta = 0;\n                int best_cost = 0;\n\n                for (int c = 1; c <= maxc; c++) {\n                    for (int cid : combo_ids_by_cost[c]) {\n                        i64 d = gain_local(x, combos[cid].add);\n                        if (d > best_delta ||\n                            (d == best_delta && c < best_cost) ||\n                            (d == best_delta && c == best_cost && cid == old_cid && best_cid != old_cid)) {\n                            best_delta = d;\n                            best_cid = cid;\n                            best_cost = c;\n                        }\n                    }\n                }\n\n                if (best_cid != 0) {\n                    sol.score += gain_add_pos(sol.board, pos, combos[best_cid].add);\n                    apply_add_pos(sol.board, pos, combos[best_cid].add);\n                    sol.used += combos[best_cid].cost;\n                    set_pos_meta(sol, pos, best_cid);\n                } else {\n                    clear_pos_meta(sol, pos);\n                }\n\n                if (best_cid != old_cid) changed = true;\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    vector<int> random_destroy(Solution &sol) {\n        vector<int> nonzero;\n        nonzero.reserve(49);\n        for (int pos = 0; pos < 49; pos++) {\n            if (sol.pos_cid[pos] != 0) nonzero.push_back(pos);\n        }\n        if (nonzero.empty()) return {};\n\n        int r = 1 + rng.next_int(min(4, (int)nonzero.size()));\n        for (int i = 0; i < r; i++) {\n            int j = i + rng.next_int((int)nonzero.size() - i);\n            swap(nonzero[i], nonzero[j]);\n        }\n\n        vector<int> removed;\n        removed.reserve(r);\n        for (int i = 0; i < r; i++) {\n            int pos = nonzero[i];\n            remove_position_combo(sol, pos);\n            removed.push_back(pos);\n        }\n        return removed;\n    }\n\n    vector<int> weak_destroy(Solution &sol) {\n        struct Item {\n            i64 gain;\n            int cost;\n            int pos;\n        };\n        vector<Item> cand;\n        cand.reserve(49);\n\n        for (int pos = 0; pos < 49; pos++) {\n            int cid = sol.pos_cid[pos];\n            if (cid == 0) continue;\n            i64 g = gain_remove_pos(sol.board, pos, combos[cid].add); // larger => weaker\n            cand.push_back({g, (int)combos[cid].cost, pos});\n        }\n        if (cand.empty()) return {};\n\n        sort(cand.begin(), cand.end(), [&](const Item& a, const Item& b) {\n            i64 lhs = a.gain * b.cost;\n            i64 rhs = b.gain * a.cost;\n            if (lhs != rhs) return lhs > rhs;\n            if (a.gain != b.gain) return a.gain > b.gain;\n            return a.pos < b.pos;\n        });\n\n        int limit = min((int)cand.size(), 6);\n        int r = 1 + rng.next_int(min(4, limit));\n\n        vector<int> chosen;\n        chosen.reserve(r);\n\n        for (int i = 0; i < r; i++) {\n            int idx = rng.next_int(limit);\n            chosen.push_back(cand[idx].pos);\n        }\n        sort(chosen.begin(), chosen.end());\n        chosen.erase(unique(chosen.begin(), chosen.end()), chosen.end());\n\n        vector<int> removed;\n        removed.reserve(chosen.size());\n        for (int pos : chosen) {\n            remove_position_combo(sol, pos);\n            removed.push_back(pos);\n        }\n        return removed;\n    }\n\n    vector<int> cluster_destroy(Solution &sol) {\n        int center = rng.next_int(49);\n        int cp = center / 7, cq = center % 7;\n\n        vector<int> cand;\n        for (int dp = -1; dp <= 1; dp++) {\n            for (int dq = -1; dq <= 1; dq++) {\n                int np = cp + dp, nq = cq + dq;\n                if (0 <= np && np < 7 && 0 <= nq && nq < 7) {\n                    int pos = np * 7 + nq;\n                    if (sol.pos_cid[pos] != 0) cand.push_back(pos);\n                }\n            }\n        }\n        if (cand.empty()) return random_destroy(sol);\n\n        int r = 1 + rng.next_int(min(5, (int)cand.size()));\n        for (int i = 0; i < r; i++) {\n            int j = i + rng.next_int((int)cand.size() - i);\n            swap(cand[i], cand[j]);\n        }\n\n        vector<int> removed;\n        removed.reserve(r);\n        for (int i = 0; i < r; i++) {\n            int pos = cand[i];\n            remove_position_combo(sol, pos);\n            removed.push_back(pos);\n        }\n        sort(removed.begin(), removed.end());\n        removed.erase(unique(removed.begin(), removed.end()), removed.end());\n        return removed;\n    }\n\n    vector<int> expand_focus_positions(const vector<int>& removed) const {\n        if (removed.empty()) return all_positions;\n\n        bool vis[49] = {};\n        vector<int> focus;\n        focus.reserve(49);\n\n        for (int pos : removed) {\n            int p = pos / 7, q = pos % 7;\n            for (int dp = -2; dp <= 2; dp++) {\n                for (int dq = -2; dq <= 2; dq++) {\n                    int np = p + dp, nq = q + dq;\n                    if (0 <= np && np < 7 && 0 <= nq && nq < 7) {\n                        int npos = np * 7 + nq;\n                        if (!vis[npos]) {\n                            vis[npos] = true;\n                            focus.push_back(npos);\n                        }\n                    }\n                }\n            }\n        }\n        return focus;\n    }\n\n    void output(const Solution &sol) const {\n        cout << sol.used << '\\n';\n        for (int pos = 0; pos < 49; pos++) {\n            int p = pos / 7;\n            int q = pos % 7;\n            for (int t = 0; t < sol.pos_count[pos]; t++) {\n                cout << (int)sol.pos_ids[pos][t] << ' ' << p << ' ' << q << '\\n';\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read_input();\n    solver.solve();\n    return 0;\n}","ahc033":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 5;\nstatic constexpr int CNUM = 25;\nstatic constexpr long long INF_SCORE = (long long)4e18;\n\nstatic chrono::steady_clock::time_point g_start;\nstatic constexpr double HARD_TIME_LIMIT_SEC = 2.82;\n\nstatic double g_deadline_sec = HARD_TIME_LIMIT_SEC;\nstatic double g_variant_start_sec = 0.0;\n\nstatic inline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - g_start).count();\n}\nstatic inline bool time_over() {\n    return elapsed_sec() > g_deadline_sec;\n}\nstatic inline double variant_elapsed_sec() {\n    return elapsed_sec() - g_variant_start_sec;\n}\nstatic inline double variant_budget_sec() {\n    return max(0.0, g_deadline_sec - g_variant_start_sec);\n}\n\nstruct Result {\n    long long score = INF_SCORE;\n    vector<string> out;\n};\n\nstruct Planner {\n    int A[N][N];\n\n    int handoff;      // 2 or 3\n    int mode;         // 0 greedy, 1 source-batch\n    int policy;       // tie-break metric\n    int ready_bias;   // source-batch threshold\n    int slot_policy;  // 0 balanced, 1 source-biased\n    int action_mode;  // 0 targeted-prefix, 1 hybrid-prefix\n\n    int src_of[CNUM], pos_of[CNUM];\n\n    int idx[N];\n    bool done[CNUM];\n    int need[N];\n\n    // 0 hidden/source, 1 buffered, 2 dispatched\n    int loc_type[CNUM];\n    pair<int,int> buf_pos[CNUM];\n    int buffer_occ[N][N];\n\n    int done_cnt = 0;\n\n    struct Crane {\n        bool alive = true;\n        int r = 0, c = 0;\n        int hold = -1;\n        bool large = false;\n    };\n    Crane cranes[N];\n\n    int cont[N][N];\n    int arrival_idx[N];\n\n    vector<string> out;\n    int T = 0;\n    bool illegal = false;\n\n    vector<int> dispatched[N];\n\n    Planner(const int inputA[N][N], int handoff_, int mode_, int policy_,\n            int ready_bias_, int slot_policy_, int action_mode_)\n        : handoff(handoff_), mode(mode_), policy(policy_),\n          ready_bias(ready_bias_), slot_policy(slot_policy_),\n          action_mode(action_mode_) {\n        memset(src_of, -1, sizeof(src_of));\n        memset(pos_of, -1, sizeof(pos_of));\n        memset(idx, 0, sizeof(idx));\n        memset(done, 0, sizeof(done));\n        memset(need, 0, sizeof(need));\n        memset(loc_type, 0, sizeof(loc_type));\n        memset(buffer_occ, -1, sizeof(buffer_occ));\n        memset(cont, -1, sizeof(cont));\n        memset(arrival_idx, 0, sizeof(arrival_idx));\n        out.assign(N, \"\");\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) A[i][j] = inputA[i][j];\n    }\n\n    static int mdist(pair<int,int> a, pair<int,int> b) {\n        return abs(a.first - b.first) + abs(a.second - b.second);\n    }\n\n    pair<int,int> cur_pos() const { return {cranes[0].r, cranes[0].c}; }\n    bool assigned_row(int d) const { return d >= 1; }\n    bool is_move(char ch) const { return ch == 'U' || ch == 'D' || ch == 'L' || ch == 'R'; }\n    bool startup_phase() const { return T < 4; }\n\n    void update_need(int d) {\n        while (need[d] <= d * N + (N - 1) && done[need[d]]) need[d]++;\n    }\n\n    bool row_pending_small(int d) const {\n        if (!assigned_row(d)) return false;\n        int t = need[d];\n        if (t > d * N + (N - 1)) return false;\n        if (cranes[d].hold == t) return true;\n        if (cont[d][handoff] == t) return true;\n        return false;\n    }\n\n    void mark_done(int id) {\n        if (id < 0 || id >= CNUM || done[id]) return;\n        done[id] = true;\n        loc_type[id] = 2;\n        done_cnt++;\n        update_need(id / N);\n    }\n\n    char decide_small(int d) const {\n        if (T < 4) return 'R';\n\n        const Crane &cr = cranes[d];\n        if (cr.hold != -1) {\n            if (cr.c < 4) return 'R';\n            return 'Q';\n        } else {\n            if (cr.c == 4) {\n                if (cont[d][handoff] == need[d]) return 'L';\n                return '.';\n            }\n            if (cr.c > handoff) {\n                if (cont[d][handoff] == need[d]) return 'L';\n                return 'R';\n            }\n            if (cr.c == handoff) {\n                if (cont[d][handoff] == need[d]) return 'P';\n                return 'R';\n            }\n            if (cr.c < 4) return 'R';\n            return '.';\n        }\n    }\n\n    void step_sim(const string &act) {\n        if (illegal) return;\n\n        for (int r = 0; r < N; r++) {\n            if (arrival_idx[r] >= N) continue;\n            if (cont[r][0] != -1) continue;\n\n            bool blocked = false;\n            for (int i = 0; i < N; i++) {\n                if (!cranes[i].alive) continue;\n                if (cranes[i].r == r && cranes[i].c == 0 && cranes[i].hold != -1) {\n                    blocked = true;\n                    break;\n                }\n            }\n            if (!blocked) {\n                cont[r][0] = A[r][arrival_idx[r]];\n                arrival_idx[r]++;\n            }\n        }\n\n        array<pair<int,int>, N> oldp, newp;\n        for (int i = 0; i < N; i++) {\n            oldp[i] = {cranes[i].r, cranes[i].c};\n            newp[i] = oldp[i];\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) {\n                if (act[i] != '.') illegal = true;\n                continue;\n            }\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n\n            if (a == 'B') {\n                if (cranes[i].hold != -1) illegal = true;\n                continue;\n            }\n            if (a == 'P') {\n                if (cranes[i].hold != -1 || cont[r][c] == -1) illegal = true;\n                continue;\n            }\n            if (a == 'Q') {\n                if (cranes[i].hold == -1 || cont[r][c] != -1) illegal = true;\n                continue;\n            }\n\n            if (is_move(a)) {\n                int nr = r, nc = c;\n                if (a == 'U') nr--;\n                if (a == 'D') nr++;\n                if (a == 'L') nc--;\n                if (a == 'R') nc++;\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) illegal = true;\n                nr = max(0, min(N - 1, nr));\n                nc = max(0, min(N - 1, nc));\n                if (!cranes[i].large && cranes[i].hold != -1 && cont[nr][nc] != -1) illegal = true;\n                newp[i] = {nr, nc};\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive || act[i] == 'B') continue;\n            for (int j = i + 1; j < N; j++) {\n                if (!cranes[j].alive || act[j] == 'B') continue;\n                if (newp[i] == newp[j]) illegal = true;\n                bool mi = (newp[i] != oldp[i]);\n                bool mj = (newp[j] != oldp[j]);\n                if (mi && mj && newp[i] == oldp[j] && newp[j] == oldp[i]) illegal = true;\n            }\n        }\n        if (illegal) return;\n\n        for (int i = 0; i < N; i++) {\n            if (cranes[i].alive && act[i] == 'B') cranes[i].alive = false;\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (cranes[i].alive && is_move(act[i])) {\n                cranes[i].r = newp[i].first;\n                cranes[i].c = newp[i].second;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (!cranes[i].alive) continue;\n            char a = act[i];\n            int r = cranes[i].r, c = cranes[i].c;\n            if (a == 'P') {\n                cranes[i].hold = cont[r][c];\n                cont[r][c] = -1;\n            } else if (a == 'Q') {\n                cont[r][c] = cranes[i].hold;\n                cranes[i].hold = -1;\n            }\n        }\n\n        for (int r = 0; r < N; r++) {\n            if (cont[r][4] != -1) {\n                dispatched[r].push_back(cont[r][4]);\n                cont[r][4] = -1;\n            }\n        }\n    }\n\n    void emit(char a0) {\n        if (illegal) return;\n        string act(N, '.');\n        act[0] = a0;\n        for (int i = 1; i < N; i++) act[i] = decide_small(i);\n\n        int small_pick_id[N], small_q_id[N];\n        for (int i = 0; i < N; i++) small_pick_id[i] = small_q_id[i] = -1;\n\n        for (int d = 1; d < N; d++) {\n            if (act[d] == 'P') small_pick_id[d] = cont[d][handoff];\n            if (act[d] == 'Q') small_q_id[d] = cranes[d].hold;\n        }\n\n        for (int i = 0; i < N; i++) out[i].push_back(act[i]);\n        step_sim(act);\n        T++;\n\n        if (illegal) return;\n\n        for (int d = 1; d < N; d++) {\n            if (small_pick_id[d] != -1) {\n                int id = small_pick_id[d];\n                if (buffer_occ[d][handoff] == id) buffer_occ[d][handoff] = -1;\n                if (loc_type[id] == 1) buf_pos[id] = {-1, -1};\n            }\n            if (small_q_id[d] != -1) {\n                mark_done(small_q_id[d]);\n            }\n        }\n    }\n\n    void move_to(int tr, int tc) {\n        int safe_col = startup_phase() ? 0 : (handoff - 1);\n        int mid = min(tc, safe_col);\n        while (!illegal && cranes[0].c > mid) emit('L');\n        while (!illegal && cranes[0].c < mid) emit('R');\n        while (!illegal && cranes[0].r < tr) emit('D');\n        while (!illegal && cranes[0].r > tr) emit('U');\n        while (!illegal && cranes[0].c < tc) emit('R');\n        while (!illegal && cranes[0].c > tc) emit('L');\n    }\n\n    bool ready_id(int id) const {\n        if (id < 0 || id >= CNUM || done[id]) return false;\n        if (loc_type[id] == 1) return buf_pos[id].first != -1;\n        int s = src_of[id];\n        return pos_of[id] == idx[s];\n    }\n\n    vector<pair<int,int>> ordinary_slots() const {\n        vector<pair<int,int>> ret;\n\n        if (startup_phase()) {\n            for (int c = 1; c <= 3; c++) {\n                if (buffer_occ[0][c] == -1) ret.push_back({0, c});\n            }\n            return ret;\n        }\n\n        for (int r = 0; r < N; r++) if (buffer_occ[r][1] == -1) ret.push_back({r, 1});\n\n        if (handoff == 3) {\n            for (int r = 0; r < N; r++) if (buffer_occ[r][2] == -1) ret.push_back({r, 2});\n            if (buffer_occ[0][3] == -1) ret.push_back({0, 3});\n        } else {\n            if (buffer_occ[0][2] == -1) ret.push_back({0, 2});\n            if (buffer_occ[0][3] == -1) ret.push_back({0, 3});\n        }\n\n        for (int r = 0; r < N; r++) {\n            if (idx[r] == N && buffer_occ[r][0] == -1) ret.push_back({r, 0});\n        }\n        return ret;\n    }\n\n    vector<pair<int,int>> overflow_slots(int exclude_row = -1) const {\n        vector<pair<int,int>> ret;\n        if (startup_phase()) return ret;\n        for (int r = 1; r < N; r++) {\n            if (r == exclude_row) continue;\n            if (buffer_occ[r][3] != -1) continue;\n            if (row_pending_small(r)) continue;\n            ret.push_back({r, 3});\n        }\n        return ret;\n    }\n\n    pair<int,int> choose_slot(int src_row, int dest_row, bool allow_overflow = true, int exclude_overflow_row = -1) const {\n        pair<int,int> best = {-1, -1};\n        int best_score = INT_MAX;\n\n        auto eval = [&](int r, int c, int extra_penalty) {\n            int score = 0;\n            if (startup_phase()) {\n                score = c;\n            } else if (slot_policy == 0) {\n                score += abs(src_row - r);\n                score += abs(r - dest_row);\n                score += c;\n                if (r == dest_row) score -= 2;\n                if (c == 1) score -= 1;\n            } else {\n                score += 2 * abs(src_row - r);\n                score += abs(r - dest_row);\n                score += c;\n                if (r == src_row) score -= 2;\n                if (r == dest_row) score -= 1;\n                if (c == 1) score -= 1;\n            }\n            score += extra_penalty;\n\n            if (score < best_score || (score == best_score && make_pair(r, c) < best)) {\n                best_score = score;\n                best = {r, c};\n            }\n        };\n\n        for (auto [r, c] : ordinary_slots()) eval(r, c, 0);\n        if (allow_overflow) for (auto [r, c] : overflow_slots(exclude_overflow_row)) eval(r, c, 6);\n        return best;\n    }\n\n    struct ReadyCand {\n        int id = -1;\n        int cost = INT_MAX;\n    };\n    struct BatchCand {\n        int s = -1;\n        int target_id = -1;\n        int target_pos = -1;\n        int cost = INT_MAX;\n    };\n    struct PrefixCand {\n        int s = -1;\n        int pos = -1;\n        int cost = INT_MAX;\n    };\n    struct PrefixEval {\n        int useful = 0;\n        int last_useful_pos = -1;\n    };\n\n    vector<ReadyCand> ready_candidates() const {\n        vector<ReadyCand> res;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (startup_phase() && d > 0) continue;\n            if (!ready_id(t)) continue;\n\n            pair<int,int> loc = (loc_type[t] == 1 ? buf_pos[t] : make_pair(src_of[t], 0));\n            int cost = mdist(cp, loc);\n            cost += abs(loc.first - d) + (d == 0 ? 4 - loc.second : handoff - loc.second);\n\n            if (!startup_phase()) {\n                if (d > 0 && handoff == 2 && buffer_occ[d][3] != -1) cost += 5;\n                if (d > 0 && handoff == 3 && buffer_occ[d][3] != -1 && buffer_occ[d][3] != t) cost += 5;\n            }\n\n            res.push_back({t, cost});\n        }\n\n        sort(res.begin(), res.end(), [](auto &a, auto &b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.id < b.id;\n        });\n        return res;\n    }\n\n    vector<BatchCand> batch_candidates() const {\n        vector<BatchCand> res;\n        auto cp = cur_pos();\n\n        for (int s = 0; s < N; s++) {\n            if (idx[s] >= N) continue;\n\n            int best_pos = INT_MAX, best_id = -1;\n            for (int d = 0; d < N; d++) {\n                int t = need[d];\n                if (t > d * N + (N - 1)) continue;\n                if (assigned_row(d) && row_pending_small(d)) continue;\n                if (src_of[t] != s) continue;\n                if (pos_of[t] < idx[s]) continue;\n\n                if (pos_of[t] < best_pos || (pos_of[t] == best_pos && t < best_id)) {\n                    best_pos = pos_of[t];\n                    best_id = t;\n                }\n            }\n            if (best_id == -1) continue;\n\n            int depth = best_pos - idx[s];\n            int d = best_id / N;\n            int travel = abs(cp.first - s) + cp.second;\n            int deliver = abs(s - d) + (d == 0 ? 4 : handoff);\n\n            int metric;\n            if (policy == 0) metric = 12 * depth + travel + deliver;\n            else if (policy == 1) metric = 10 * depth + 2 * travel + deliver;\n            else metric = 9 * depth + travel + 2 * deliver;\n\n            res.push_back({s, best_id, best_pos, metric});\n        }\n\n        sort(res.begin(), res.end(), [](auto &a, auto &b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.target_pos != b.target_pos) return a.target_pos < b.target_pos;\n            if (a.target_id != b.target_id) return a.target_id < b.target_id;\n            return a.s < b.s;\n        });\n        return res;\n    }\n\n    PrefixEval eval_prefix(int s, int end_pos) const {\n        PrefixEval pe;\n        int tmp_need[N];\n        for (int d = 0; d < N; d++) tmp_need[d] = need[d];\n\n        for (int p = idx[s]; p <= end_pos; p++) {\n            int x = A[s][p];\n            int d = x / N;\n            if (d == 0) {\n                if (x == tmp_need[0]) {\n                    pe.useful++;\n                    pe.last_useful_pos = p;\n                    tmp_need[0]++;\n                }\n            } else if (!startup_phase() && !row_pending_small(d)) {\n                if (x == tmp_need[d]) {\n                    pe.useful++;\n                    pe.last_useful_pos = p;\n                    tmp_need[d]++;\n                }\n            }\n        }\n        return pe;\n    }\n\n    vector<PrefixCand> prefix_candidates() const {\n        vector<PrefixCand> all;\n        auto cp = cur_pos();\n\n        for (int s = 0; s < N; s++) {\n            if (idx[s] >= N) continue;\n\n            int travel = abs(cp.first - s) + cp.second;\n\n            vector<int> targets;\n            for (int d = 0; d < N; d++) {\n                int t = need[d];\n                if (t > d * N + (N - 1)) continue;\n                if (assigned_row(d) && row_pending_small(d)) continue;\n                if (src_of[t] == s && pos_of[t] >= idx[s]) targets.push_back(pos_of[t]);\n            }\n            sort(targets.begin(), targets.end());\n            targets.erase(unique(targets.begin(), targets.end()), targets.end());\n\n            vector<int> poslist;\n            poslist.push_back(idx[s]);\n            if (idx[s] + 1 < N) poslist.push_back(idx[s] + 1);\n            if (!targets.empty()) poslist.push_back(targets[0]);\n            if ((int)targets.size() >= 2) poslist.push_back(targets[1]);\n            if (N - 1 - idx[s] <= 2) poslist.push_back(N - 1);\n\n            int front = A[s][idx[s]];\n            int fd = front / N;\n            bool front_directly_useful = (front == need[fd] &&\n                                          (!assigned_row(fd) || !row_pending_small(fd)) &&\n                                          (!startup_phase() || fd == 0));\n\n            sort(poslist.begin(), poslist.end());\n            poslist.erase(unique(poslist.begin(), poslist.end()), poslist.end());\n\n            vector<PrefixCand> local;\n\n            for (int pos : poslist) {\n                if (pos < idx[s]) continue;\n                int len = pos - idx[s] + 1;\n\n                if (len == 1 && front_directly_useful) continue;\n\n                int cost = 3 * travel + 5 * len;\n                if (!targets.empty() && pos == targets[0]) cost -= 10;\n                if ((int)targets.size() >= 2 && pos == targets[1]) cost -= 4;\n                if (front_directly_useful) cost -= 6;\n                if (pos == N - 1) cost += 1;\n\n                local.push_back({s, pos, cost});\n            }\n\n            if (action_mode == 1) {\n                PrefixCand best_extra;\n                bool found = false;\n\n                for (int pos = idx[s]; pos < N; pos++) {\n                    if (binary_search(poslist.begin(), poslist.end(), pos)) continue;\n                    int len = pos - idx[s] + 1;\n                    PrefixEval pe = eval_prefix(s, pos);\n\n                    if (pe.useful == 0 && len > 2) continue;\n\n                    int cost = 3 * travel + 5 * len;\n                    cost -= 10 * pe.useful;\n                    if (pe.useful >= 2) cost -= 2 * (pe.useful - 1);\n                    if (pe.last_useful_pos == pos) cost -= 2;\n                    if (pos == N - 1) cost += 1;\n\n                    if (!found || cost < best_extra.cost || (cost == best_extra.cost && pos < best_extra.pos)) {\n                        found = true;\n                        best_extra = {s, pos, cost};\n                    }\n                }\n\n                if (found) local.push_back(best_extra);\n            }\n\n            sort(local.begin(), local.end(), [](const PrefixCand &a, const PrefixCand &b) {\n                if (a.cost != b.cost) return a.cost < b.cost;\n                if (a.pos != b.pos) return a.pos < b.pos;\n                return a.s < b.s;\n            });\n\n            int keep = min<int>(action_mode == 0 ? 4 : 5, local.size());\n            for (int i = 0; i < keep; i++) all.push_back(local[i]);\n        }\n\n        sort(all.begin(), all.end(), [](const PrefixCand &a, const PrefixCand &b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            if (a.pos != b.pos) return a.pos < b.pos;\n            return a.s < b.s;\n        });\n        return all;\n    }\n\n    ReadyCand choose_ready_opt() const {\n        auto v = ready_candidates();\n        if (v.empty()) return {};\n        return v[0];\n    }\n\n    BatchCand choose_batch_opt() const {\n        auto v = batch_candidates();\n        if (v.empty()) return {};\n        return v[0];\n    }\n\n    int choose_target_row() const {\n        int best_d = -1;\n        long long best_metric = INF_SCORE;\n        auto cp = cur_pos();\n\n        for (int d = 0; d < N; d++) {\n            int t = need[d];\n            if (t > d * N + (N - 1)) continue;\n            if (assigned_row(d) && row_pending_small(d)) continue;\n            if (ready_id(t)) continue;\n\n            int s = src_of[t];\n            int depth = pos_of[t] - idx[s];\n            int front = (idx[s] < N ? A[s][idx[s]] : INT_MAX);\n            int travel = abs(cp.first - s) + cp.second;\n            int align = abs(s - d);\n\n            long long metric;\n            if (policy == 0) {\n                metric = (((long long)depth) << 30) + (((long long)front) << 15) + (((long long)travel) << 7) + d;\n            } else if (policy == 1) {\n                metric = (((long long)depth) << 30) + (((long long)travel) << 15) + (((long long)front) << 7) + d;\n            } else {\n                metric = ((10LL * depth + 2LL * travel + align) << 10) + d;\n            }\n\n            if (metric < best_metric) {\n                best_metric = metric;\n                best_d = d;\n            }\n        }\n        return best_d;\n    }\n\n    void pick_id(int id) {\n        if (loc_type[id] == 1) {\n            auto [r, c] = buf_pos[id];\n            move_to(r, c);\n            if (illegal) return;\n            emit('P');\n            if (illegal) return;\n            buffer_occ[r][c] = -1;\n            loc_type[id] = 0;\n            buf_pos[id] = {-1, -1};\n        } else {\n            int s = src_of[id];\n            move_to(s, 0);\n            if (illegal) return;\n            emit('P');\n            if (illegal) return;\n            idx[s]++;\n        }\n    }\n\n    void direct_dispatch_large_row0(int id) {\n        move_to(0, 4);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        mark_done(id);\n    }\n\n    void place_on_row_slot(int id, int d);\n\n    void clear_cell(int r, int c) {\n        int x = buffer_occ[r][c];\n        if (x == -1) return;\n        if (r >= 1 && row_pending_small(r)) return;\n\n        move_to(r, c);\n        if (illegal) return;\n        emit('P');\n        if (illegal) return;\n\n        buffer_occ[r][c] = -1;\n        loc_type[x] = 0;\n        buf_pos[x] = {-1, -1};\n\n        int d = x / N;\n        if (d == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (!startup_phase() && d > 0 && x == need[d] && !row_pending_small(d)) {\n            place_on_row_slot(x, d);\n            return;\n        }\n\n        auto slot = choose_slot(r, d, true, r);\n        if (slot.first == -1) {\n            if (startup_phase()) {\n                while (!illegal && startup_phase()) emit('.');\n                if (illegal) return;\n                slot = choose_slot(r, d, true, r);\n            }\n        }\n        if (slot.first == -1) {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(x);\n            return;\n        }\n\n        move_to(slot.first, slot.second);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void dispatch_ready(int id) {\n        pick_id(id);\n        if (illegal) return;\n        int d = id / N;\n        if (d == 0) direct_dispatch_large_row0(id);\n        else place_on_row_slot(id, d);\n    }\n\n    void buffer_or_handle_front(int s) {\n        int x = A[s][idx[s]];\n        move_to(s, 0);\n        if (illegal) return;\n        emit('P');\n        if (illegal) return;\n        idx[s]++;\n\n        int d = x / N;\n        if (d == 0 && x == need[0]) {\n            direct_dispatch_large_row0(x);\n            return;\n        }\n        if (!startup_phase() && d > 0 && x == need[d] && !row_pending_small(d)) {\n            place_on_row_slot(x, d);\n            return;\n        }\n\n        auto slot = choose_slot(s, d, true, -1);\n        if (slot.first == -1 && startup_phase()) {\n            while (!illegal && startup_phase()) emit('.');\n            if (illegal) return;\n            if (d > 0 && x == need[d] && !row_pending_small(d)) {\n                place_on_row_slot(x, d);\n                return;\n            }\n            slot = choose_slot(s, d, true, -1);\n        }\n\n        if (slot.first == -1) {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(x);\n            return;\n        }\n\n        move_to(slot.first, slot.second);\n        if (illegal) return;\n        emit('Q');\n        if (illegal) return;\n        loc_type[x] = 1;\n        buf_pos[x] = slot;\n        buffer_occ[slot.first][slot.second] = x;\n    }\n\n    void process_source_batch(const BatchCand &bo) {\n        int s = bo.s;\n        int target_pos = bo.target_pos;\n        while (!illegal && T < 10000 && idx[s] <= target_pos) {\n            int before = idx[s];\n            buffer_or_handle_front(s);\n            if (illegal) return;\n            if (idx[s] <= before) break;\n        }\n    }\n\n    void process_source_to_pos(int s, int target_pos) {\n        if (s < 0 || s >= N) return;\n        if (idx[s] >= N) return;\n        target_pos = min(target_pos, N - 1);\n        while (!illegal && T < 10000 && idx[s] <= target_pos) {\n            int before = idx[s];\n            buffer_or_handle_front(s);\n            if (illegal) return;\n            if (idx[s] <= before) break;\n        }\n    }\n\n    long long exact_score() const {\n        if (illegal) return INF_SCORE;\n\n        long long M0 = T, M1 = 0, M2 = 0, M3 = 0;\n        int total_dispatched = 0;\n\n        for (int r = 0; r < N; r++) {\n            vector<int> corr;\n            for (int x : dispatched[r]) {\n                total_dispatched++;\n                if (x / N != r) M2++;\n                else corr.push_back(x);\n            }\n            for (int i = 0; i < (int)corr.size(); i++) {\n                for (int j = i + 1; j < (int)corr.size(); j++) {\n                    if (corr[i] > corr[j]) M1++;\n                }\n            }\n        }\n        M3 = CNUM - total_dispatched;\n        return M0 + 100LL * M1 + 10000LL * M2 + 1000000LL * M3;\n    }\n\n    void init() {\n        for (int r = 0; r < N; r++) {\n            for (int j = 0; j < N; j++) {\n                int x = A[r][j];\n                src_of[x] = r;\n                pos_of[x] = j;\n            }\n        }\n        for (int d = 0; d < N; d++) need[d] = d * N;\n\n        for (int i = 0; i < N; i++) {\n            cranes[i].alive = true;\n            cranes[i].r = i;\n            cranes[i].c = 0;\n            cranes[i].hold = -1;\n            cranes[i].large = (i == 0);\n        }\n    }\n\n    void run_default_loop() {\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            if (mode == 0) {\n                auto ro = choose_ready_opt();\n                if (ro.id != -1) {\n                    dispatch_ready(ro.id);\n                    continue;\n                }\n                int d = choose_target_row();\n                if (d == -1) {\n                    bool pending = false;\n                    for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n                    if (pending) {\n                        if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n                        else emit('.');\n                        continue;\n                    }\n                    break;\n                }\n                int t = need[d];\n                int s = src_of[t];\n                if (idx[s] >= N) break;\n                buffer_or_handle_front(s);\n            } else {\n                auto ro = choose_ready_opt();\n                auto bo = choose_batch_opt();\n\n                if (bo.s == -1) {\n                    if (ro.id != -1) {\n                        dispatch_ready(ro.id);\n                        continue;\n                    }\n                    bool pending = false;\n                    for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n                    if (pending) {\n                        if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n                        else emit('.');\n                        continue;\n                    }\n                    break;\n                }\n\n                bool take_ready = false;\n                if (ro.id != -1 && ro.cost <= bo.cost + ready_bias) take_ready = true;\n\n                if (take_ready) dispatch_ready(ro.id);\n                else process_source_batch(bo);\n            }\n        }\n    }\n\n    void drain_and_fallback() {\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            bool pending = false;\n            for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n            if (!pending) break;\n            if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n            else emit('.');\n        }\n\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            auto ro = choose_ready_opt();\n            if (ro.id != -1) {\n                dispatch_ready(ro.id);\n                continue;\n            }\n            bool progressed = false;\n            for (int s = 0; s < N && !progressed; s++) {\n                if (idx[s] < N) {\n                    buffer_or_handle_front(s);\n                    progressed = true;\n                }\n            }\n            if (progressed) continue;\n\n            bool pending = false;\n            for (int r = 1; r < N; r++) if (row_pending_small(r)) pending = true;\n            if (pending) {\n                if (cranes[0].c > (startup_phase() ? 0 : handoff - 1)) emit('L');\n                else emit('.');\n                continue;\n            }\n            break;\n        }\n    }\n\n    void finish_default() {\n        run_default_loop();\n        drain_and_fallback();\n    }\n\n    Result make_result() const {\n        Result res;\n        res.score = exact_score();\n        res.out = out.empty() ? vector<string>(N, \".\") : out;\n        if (res.out[0].empty()) res.out.assign(N, \".\");\n        return res;\n    }\n\n    struct Action {\n        int type; // 0 ready(id), 1 prefix(source,pos)\n        int a, b;\n        int est;\n    };\n\n    vector<Action> enumerate_actions(int max_total) const {\n        vector<Action> acts;\n\n        auto rc = ready_candidates();\n        auto pc = prefix_candidates();\n\n        int cap_ready = 4;\n        int cap_prefix = 12;\n\n        for (int i = 0; i < (int)rc.size() && i < cap_ready; i++) {\n            acts.push_back({0, rc[i].id, -1, rc[i].cost});\n        }\n        for (int i = 0; i < (int)pc.size() && i < cap_prefix; i++) {\n            acts.push_back({1, pc[i].s, pc[i].pos, pc[i].cost});\n        }\n\n        sort(acts.begin(), acts.end(), [](const Action &x, const Action &y) {\n            if (x.est != y.est) return x.est < y.est;\n            if (x.type != y.type) return x.type < y.type;\n            if (x.a != y.a) return x.a < y.a;\n            return x.b < y.b;\n        });\n\n        vector<Action> uniq;\n        for (auto &a : acts) {\n            bool dup = false;\n            for (auto &b : uniq) {\n                if (a.type == b.type && a.a == b.a && a.b == b.b) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) uniq.push_back(a);\n            if ((int)uniq.size() >= max_total) break;\n        }\n        return uniq;\n    }\n\n    void apply_action(const Action &a) {\n        if (a.type == 0) dispatch_ready(a.a);\n        else process_source_to_pos(a.a, a.b);\n    }\n\n    long long eval_future(int depth_left, int max_actions) {\n        if (illegal) return INF_SCORE;\n        if (time_over()) {\n            finish_default();\n            return exact_score();\n        }\n        if (depth_left <= 0) {\n            finish_default();\n            return exact_score();\n        }\n\n        int local_actions = max_actions;\n        if (depth_left >= 2) local_actions = min(local_actions, 6);\n        if (depth_left >= 3) local_actions = min(local_actions, 5);\n\n        auto acts = enumerate_actions(local_actions);\n        if (acts.empty()) {\n            finish_default();\n            return exact_score();\n        }\n\n        long long best = INF_SCORE;\n        for (auto &a : acts) {\n            if (time_over()) break;\n            Planner tmp = *this;\n            tmp.apply_action(a);\n            if (tmp.illegal) continue;\n            best = min(best, tmp.eval_future(depth_left - 1, max_actions));\n        }\n\n        if (best == INF_SCORE) {\n            finish_default();\n            return exact_score();\n        }\n        return best;\n    }\n\n    Result solve_default() {\n        init();\n        finish_default();\n        return make_result();\n    }\n\n    Result solve_rollout_adaptive(int base_depth, int max_actions) {\n        init();\n\n        int root_steps = 0;\n        while (!illegal && done_cnt < CNUM && T < 10000) {\n            if (time_over()) {\n                finish_default();\n                break;\n            }\n\n            auto acts = enumerate_actions(max_actions);\n            if (acts.empty()) {\n                finish_default();\n                break;\n            }\n\n            int use_depth = base_depth;\n            double vb = max(1e-9, variant_budget_sec());\n            double ve = variant_elapsed_sec();\n\n            if (done_cnt >= 18 && ve < vb * 0.90) use_depth = max(use_depth, 4);\n            else if (root_steps < 6 && ve < vb * 0.55) use_depth = max(use_depth, 3);\n            else if (root_steps < 12 && ve < vb * 0.80) use_depth = max(use_depth, 2);\n\n            int root_actions = max_actions;\n            if (use_depth >= 4) root_actions = min(root_actions, 5);\n            else if (use_depth >= 3) root_actions = min(root_actions, 7);\n            if ((int)acts.size() > root_actions) acts.resize(root_actions);\n\n            long long bestScore = INF_SCORE;\n            int bestIdx = -1;\n\n            for (int i = 0; i < (int)acts.size(); i++) {\n                if (time_over()) break;\n                Planner tmp = *this;\n                tmp.apply_action(acts[i]);\n                if (tmp.illegal) continue;\n                long long sc = tmp.eval_future(use_depth - 1, max_actions);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    bestIdx = i;\n                }\n            }\n\n            if (bestIdx == -1) {\n                finish_default();\n                break;\n            }\n            apply_action(acts[bestIdx]);\n            root_steps++;\n        }\n\n        drain_and_fallback();\n        return make_result();\n    }\n};\n\nvoid Planner::place_on_row_slot(int id, int d) {\n    if (d == 0) {\n        direct_dispatch_large_row0(id);\n        return;\n    }\n\n    if (startup_phase()) {\n        auto slot = choose_slot(cranes[0].r, d, false, -1);\n        if (slot.first == -1) {\n            while (!illegal && startup_phase()) emit('.');\n            if (illegal) return;\n        } else {\n            move_to(slot.first, slot.second);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            loc_type[id] = 1;\n            buf_pos[id] = slot;\n            buffer_occ[slot.first][slot.second] = id;\n            return;\n        }\n    }\n\n    if (handoff == 3) {\n        if (buffer_occ[d][3] != -1 && buffer_occ[d][3] != id) {\n            clear_cell(d, 3);\n            if (illegal) return;\n        }\n        if (buffer_occ[d][3] == -1) {\n            move_to(d, 3);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            loc_type[id] = 1;\n            buf_pos[id] = {d, 3};\n            buffer_occ[d][3] = id;\n        } else {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(id);\n        }\n    } else {\n        if (buffer_occ[d][3] != -1) {\n            clear_cell(d, 3);\n            if (illegal) return;\n        }\n        if (buffer_occ[d][2] != -1 && buffer_occ[d][2] != id) {\n            clear_cell(d, 2);\n            if (illegal) return;\n        }\n        if (buffer_occ[d][2] == -1 && buffer_occ[d][3] == -1) {\n            move_to(d, 2);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            loc_type[id] = 1;\n            buf_pos[id] = {d, 2};\n            buffer_occ[d][2] = id;\n        } else {\n            move_to(d, 4);\n            if (illegal) return;\n            emit('Q');\n            if (illegal) return;\n            mark_done(id);\n        }\n    }\n}\n\nstruct Variant {\n    int handoff, mode, policy, ready_bias, slot_policy, action_mode;\n    int rollout_depth;\n    int max_actions;\n};\n\nstatic Result run_variant(const int A[N][N], const Variant &v, double budget) {\n    double now = elapsed_sec();\n    g_variant_start_sec = now;\n    g_deadline_sec = min(HARD_TIME_LIMIT_SEC - 0.005, now + budget);\n    Planner planner(A, v.handoff, v.mode, v.policy, v.ready_bias, v.slot_policy, v.action_mode);\n    if (v.rollout_depth > 0) return planner.solve_rollout_adaptive(v.rollout_depth, v.max_actions);\n    return planner.solve_default();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    g_start = chrono::steady_clock::now();\n\n    int n;\n    cin >> n;\n    int A[N][N];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) cin >> A[i][j];\n\n    Result best;\n\n    // Phase 1: scouts\n    vector<Variant> scouts = {\n        {2, 1, 1, 2, 1, 0, 2, 7},\n        {3, 1, 1, 2, 1, 0, 2, 7},\n        {2, 1, 1, 2, 1, 1, 2, 7},\n        {3, 1, 1, 2, 1, 1, 2, 7},\n        {2, 1, 2, 2, 1, 0, 2, 7},\n        {3, 1, 2, 2, 1, 0, 2, 7},\n        {2, 1, 1, 2, 0, 0, 2, 7},\n        {3, 1, 1, 2, 0, 0, 2, 7},\n    };\n    vector<double> scout_budget = {0.05, 0.05, 0.05, 0.05, 0.04, 0.04, 0.03, 0.03};\n\n    vector<pair<long long,int>> ranking;\n    for (int i = 0; i < (int)scouts.size(); i++) {\n        double left = HARD_TIME_LIMIT_SEC - 0.01 - elapsed_sec();\n        if (left <= 0.0) break;\n        Result cur = run_variant(A, scouts[i], min(left, scout_budget[i]));\n        if (cur.score < best.score) best = cur;\n        ranking.push_back({cur.score, i});\n    }\n\n    sort(ranking.begin(), ranking.end());\n\n    // Phase 2: deepen top scout families\n    vector<double> deep_budget = {0.95, 0.72, 0.42, 0.22};\n    for (int rank = 0; rank < (int)deep_budget.size() && rank < (int)ranking.size(); rank++) {\n        double left = HARD_TIME_LIMIT_SEC - 0.01 - elapsed_sec();\n        if (left <= 0.0) break;\n\n        Variant v = scouts[ranking[rank].second];\n        v.rollout_depth = 3;\n        v.max_actions = 9;\n        Result cur = run_variant(A, v, min(left, deep_budget[rank]));\n        if (cur.score < best.score) best = cur;\n\n        // For the top 2, also try the paired action mode or slot policy variant cheaply.\n        if (rank < 2) {\n            left = HARD_TIME_LIMIT_SEC - 0.01 - elapsed_sec();\n            if (left > 0.0) {\n                Variant alt = v;\n                alt.rollout_depth = 2;\n                alt.max_actions = 8;\n                alt.action_mode ^= 1;\n                Result cur2 = run_variant(A, alt, min(left, 0.12));\n                if (cur2.score < best.score) best = cur2;\n            }\n            left = HARD_TIME_LIMIT_SEC - 0.01 - elapsed_sec();\n            if (left > 0.0) {\n                Variant alt2 = v;\n                alt2.rollout_depth = 2;\n                alt2.max_actions = 8;\n                alt2.slot_policy ^= 1;\n                Result cur3 = run_variant(A, alt2, min(left, 0.10));\n                if (cur3.score < best.score) best = cur3;\n            }\n        }\n    }\n\n    // Final ultra-cheap backups if time remains.\n    vector<Variant> backups = {\n        {2, 1, 1, 6, 1, 0, 2, 8},\n        {3, 1, 1, 6, 1, 0, 2, 8},\n        {2, 0, 2, 0, 0, 0, 0, 0},\n        {3, 0, 1, 0, 0, 0, 0, 0},\n    };\n    vector<double> backup_budget = {0.05, 0.04, 0.02, 0.02};\n\n    for (int i = 0; i < (int)backups.size(); i++) {\n        double left = HARD_TIME_LIMIT_SEC - 0.01 - elapsed_sec();\n        if (left <= 0.0) break;\n        Result cur = run_variant(A, backups[i], min(left, backup_budget[i]));\n        if (cur.score < best.score) best = cur;\n    }\n\n    if (best.out.empty()) best.out.assign(N, \".\");\n    for (int i = 0; i < N; i++) cout << best.out[i] << '\\n';\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Point {\n    int r, c;\n};\n\nstruct EvalInfo {\n    long long cost;\n    int borrow;\n};\n\nstruct Candidate {\n    long long cost;\n    int borrow;\n    vector<int> path;\n    uint64_t hs;\n};\n\nstruct State {\n    vector<int> path;\n    vector<int> pos;\n    long long cost;\n};\n\nstruct XorShift64 {\n    uint64_t x;\n    explicit XorShift64(uint64_t seed = 88172645463393265ull) : x(seed) {}\n    uint64_t next_u64() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    uint32_t next_u32() { return (uint32_t)next_u64(); }\n    int next_int(int n) { return (int)(next_u32() % (uint32_t)n); }\n    double next_double() {\n        return (next_u32() + 0.5) * (1.0 / 4294967296.0);\n    }\n};\n\nstatic constexpr long long INF64 = (1LL << 62);\n\nint N, M;\nvector<int> H1;\nlong long BASE_COST = 0;\n\nint rr_[400], cc_[400];\nint dist0_[400];\nint distmat_[400][400];\nbool adjmat_[400][400];\nvector<int> neigh_[400];\n\nchrono::steady_clock::time_point TIME_BEGIN;\n\ninline double elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - TIME_BEGIN).count();\n}\n\ninline bool better_eval(const EvalInfo& a, const EvalInfo& b) {\n    if (a.cost != b.cost) return a.cost < b.cost;\n    return a.borrow < b.borrow;\n}\n\nuint64_t hash_order(const vector<int>& path) {\n    uint64_t h = 1469598103934665603ull;\n    for (int x : path) {\n        h ^= (uint64_t)(x + 1);\n        h *= 1099511628211ull;\n    }\n    return h;\n}\n\nPoint apply_sym(Point p, int sym, int N) {\n    if (sym >= 4) {\n        p.c = N - 1 - p.c;\n        sym -= 4;\n    }\n    for (int k = 0; k < sym; k++) {\n        int nr = p.c;\n        int nc = N - 1 - p.r;\n        p.r = nr;\n        p.c = nc;\n    }\n    return p;\n}\n\nvector<Point> transform_order(const vector<Point>& base, int sym, bool rev, int N) {\n    vector<Point> v;\n    v.reserve(base.size());\n    for (auto p : base) v.push_back(apply_sym(p, sym, N));\n    if (rev) reverse(v.begin(), v.end());\n    return v;\n}\n\nbool validate_order(const vector<Point>& ord, int N, bool cycle) {\n    if ((int)ord.size() != N * N) return false;\n    vector<int> seen(N * N, 0);\n    for (auto p : ord) {\n        if (p.r < 0 || p.r >= N || p.c < 0 || p.c >= N) return false;\n        int id = p.r * N + p.c;\n        if (seen[id]) return false;\n        seen[id] = 1;\n    }\n    for (int i = 0; i + 1 < (int)ord.size(); i++) {\n        int d = abs(ord[i].r - ord[i + 1].r) + abs(ord[i].c - ord[i + 1].c);\n        if (d != 1) return false;\n    }\n    if (cycle) {\n        int d = abs(ord.back().r - ord.front().r) + abs(ord.back().c - ord.front().c);\n        if (d != 1) return false;\n    }\n    return true;\n}\n\nvector<Point> make_base_cycle(int N) {\n    vector<Point> cyc;\n    cyc.reserve(N * N);\n\n    for (int r = 0; r < N; r++) cyc.push_back({r, 0});\n    for (int c = 1; c < N; c++) {\n        if (c & 1) {\n            for (int r = N - 1; r >= 1; r--) cyc.push_back({r, c});\n        } else {\n            for (int r = 1; r < N; r++) cyc.push_back({r, c});\n        }\n    }\n    cyc.push_back({0, N - 1});\n    for (int c = N - 2; c >= 1; c--) cyc.push_back({0, c});\n\n    return cyc;\n}\n\nvector<Point> make_row_snake(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    for (int r = 0; r < N; r++) {\n        if ((r & 1) == 0) {\n            for (int c = 0; c < N; c++) ord.push_back({r, c});\n        } else {\n            for (int c = N - 1; c >= 0; c--) ord.push_back({r, c});\n        }\n    }\n    return ord;\n}\n\nvector<Point> make_spiral(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\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++) ord.push_back({top, c});\n        top++;\n        for (int r = top; r <= bottom; r++) ord.push_back({r, right});\n        right--;\n        if (top <= bottom) {\n            for (int c = right; c >= left; c--) ord.push_back({bottom, c});\n            bottom--;\n        }\n        if (left <= right) {\n            for (int r = bottom; r >= top; r--) ord.push_back({r, left});\n            left++;\n        }\n    }\n    return ord;\n}\n\nint sgn(int x) { return (x > 0) - (x < 0); }\n\nvoid gilbert2d(int x, int y, int ax, int ay, int bx, int by, vector<Point>& out) {\n    int w = abs(ax + ay);\n    int h = abs(bx + by);\n\n    int dax = sgn(ax), day = sgn(ay);\n    int dbx = sgn(bx), dby = sgn(by);\n\n    if (h == 1) {\n        for (int i = 0; i < w; i++) {\n            out.push_back({y, x});\n            x += dax;\n            y += day;\n        }\n        return;\n    }\n    if (w == 1) {\n        for (int i = 0; i < h; i++) {\n            out.push_back({y, x});\n            x += dbx;\n            y += dby;\n        }\n        return;\n    }\n\n    int ax2 = ax / 2, ay2 = ay / 2;\n    int bx2 = bx / 2, by2 = by / 2;\n\n    int w2 = abs(ax2 + ay2);\n    int h2 = abs(bx2 + by2);\n\n    if (2 * w > 3 * h) {\n        if ((w2 & 1) && (w > 2)) {\n            ax2 += dax;\n            ay2 += day;\n        }\n        gilbert2d(x, y, ax2, ay2, bx, by, out);\n        gilbert2d(x + ax2, y + ay2, ax - ax2, ay - ay2, bx, by, out);\n    } else {\n        if ((h2 & 1) && (h > 2)) {\n            bx2 += dbx;\n            by2 += dby;\n        }\n        gilbert2d(x, y, bx2, by2, ax2, ay2, out);\n        gilbert2d(x + bx2, y + by2, ax, ay, bx - bx2, by - by2, out);\n        gilbert2d(\n            x + (ax - dax) + (bx2 - dbx),\n            y + (ay - day) + (by2 - dby),\n            -bx2, -by2, -(ax - ax2), -(ay - ay2), out\n        );\n    }\n}\n\nvector<Point> make_gilbert(int N) {\n    vector<Point> ord;\n    ord.reserve(N * N);\n    gilbert2d(0, 0, N, 0, 0, N, ord);\n    return ord;\n}\n\nvector<int> points_to_ids(const vector<Point>& v) {\n    vector<int> ids;\n    ids.reserve(v.size());\n    for (auto p : v) ids.push_back(p.r * N + p.c);\n    return ids;\n}\n\nvoid build_pos(const vector<int>& path, vector<int>& pos) {\n    pos.assign(M, -1);\n    for (int i = 0; i < M; i++) pos[path[i]] = i;\n}\n\nEvalInfo eval_path_direction(const vector<int>& path, bool rev) {\n    long long cur = 0, min_pref = 0, sum_pref = 0;\n    if (!rev) {\n        for (int i = 0; i < M; i++) {\n            cur += H1[path[i]];\n            if (cur < min_pref) min_pref = cur;\n            if (i + 1 < M) sum_pref += cur;\n        }\n        long long k = -min_pref;\n        int s = path[0], t = path[M - 1];\n        int ret = (k > 0 ? distmat_[s][t] : 0);\n        long long cost =\n            BASE_COST +\n            2LL * k +\n            100LL * (dist0_[s] + (M - 1) + ret) +\n            sum_pref +\n            k * 1LL * ((M - 1) + ret);\n        return {cost, (int)k};\n    } else {\n        for (int i = M - 1; i >= 0; i--) {\n            cur += H1[path[i]];\n            if (cur < min_pref) min_pref = cur;\n            if (i > 0) sum_pref += cur;\n        }\n        long long k = -min_pref;\n        int s = path[M - 1], t = path[0];\n        int ret = (k > 0 ? distmat_[s][t] : 0);\n        long long cost =\n            BASE_COST +\n            2LL * k +\n            100LL * (dist0_[s] + (M - 1) + ret) +\n            sum_pref +\n            k * 1LL * ((M - 1) + ret);\n        return {cost, (int)k};\n    }\n}\n\npair<EvalInfo, int> eval_cycle_best_shift(const vector<int>& cyc) {\n    static long long P[405];\n    static long long pref[410];\n\n    P[0] = 0;\n    for (int i = 0; i < M; i++) P[i + 1] = P[i] + H1[cyc[i]];\n\n    long long minP = P[0];\n    for (int st = 1; st < M; st++) minP = min(minP, P[st]);\n\n    pref[0] = 0;\n    for (int i = 0; i <= M; i++) pref[i + 1] = pref[i] + P[i];\n\n    EvalInfo best{INF64, 0};\n    int best_st = 0;\n\n    for (int st = 0; st < M; st++) {\n        if (P[st] != minP) continue;\n\n        long long sum1 = pref[M + 1] - pref[st + 1];\n        long long sum2 = (st >= 2 ? pref[st] - pref[1] : 0);\n        long long carry = sum1 + sum2 - 1LL * (M - 1) * P[st];\n\n        int s = cyc[st];\n        long long cost = BASE_COST + 100LL * (dist0_[s] + (M - 1)) + carry;\n        EvalInfo cur{cost, 0};\n        if (better_eval(cur, best)) {\n            best = cur;\n            best_st = st;\n        }\n    }\n    return {best, best_st};\n}\n\nvoid orient_best_inplace(vector<int>& path, EvalInfo& best_eval) {\n    EvalInfo best = eval_path_direction(path, false);\n    int mode = 0;\n    int best_st = 0;\n\n    EvalInfo revp = eval_path_direction(path, true);\n    if (better_eval(revp, best)) {\n        best = revp;\n        mode = 1;\n    }\n\n    if (adjmat_[path.front()][path.back()]) {\n        auto [cycf, stf] = eval_cycle_best_shift(path);\n        if (better_eval(cycf, best)) {\n            best = cycf;\n            mode = 2;\n            best_st = stf;\n        }\n\n        vector<int> rev_path = path;\n        reverse(rev_path.begin(), rev_path.end());\n        auto [cycr, str] = eval_cycle_best_shift(rev_path);\n        if (better_eval(cycr, best)) {\n            best = cycr;\n            mode = 3;\n            best_st = str;\n        }\n    }\n\n    if (mode == 1) {\n        reverse(path.begin(), path.end());\n    } else if (mode == 2) {\n        rotate(path.begin(), path.begin() + best_st, path.end());\n    } else if (mode == 3) {\n        reverse(path.begin(), path.end());\n        rotate(path.begin(), path.begin() + best_st, path.end());\n    }\n\n    best_eval = best;\n}\n\nbool random_backbite(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    int first_side = rng.next_int(2);\n    for (int rep = 0; rep < 2; rep++) {\n        int side = first_side ^ rep;\n        if (side == 0) {\n            int ep = path[0];\n            int forbidden = path[1];\n            int cand[4], cnt = 0;\n            for (int u : neigh_[ep]) if (u != forbidden) cand[cnt++] = u;\n            if (cnt == 0) continue;\n            int u = cand[rng.next_int(cnt)];\n            int i = pos[u];\n            if (i <= 1) continue;\n            reverse(path.begin(), path.begin() + i);\n            for (int k = 0; k < i; k++) pos[path[k]] = k;\n            return true;\n        } else {\n            int ep = path[M - 1];\n            int forbidden = path[M - 2];\n            int cand[4], cnt = 0;\n            for (int u : neigh_[ep]) if (u != forbidden) cand[cnt++] = u;\n            if (cnt == 0) continue;\n            int u = cand[rng.next_int(cnt)];\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            reverse(path.begin() + i + 1, path.end());\n            for (int k = i + 1; k < M; k++) pos[path[k]] = k;\n            return true;\n        }\n    }\n    return false;\n}\n\nbool random_two_opt(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    for (int tries = 0; tries < 32; tries++) {\n        int i = rng.next_int(M - 1);\n        int a = path[i];\n        int b = path[i + 1];\n        int prev = (i > 0 ? path[i - 1] : -1);\n\n        int candj[4], cnt = 0;\n        for (int u : neigh_[a]) {\n            if (u == b || u == prev) continue;\n            int j = pos[u];\n            if (j <= i + 1) continue;\n            if (j == M - 1 || adjmat_[b][path[j + 1]]) {\n                if (!(i == 0 && j == M - 1)) candj[cnt++] = j;\n            }\n        }\n        if (cnt == 0) continue;\n\n        int j = candj[rng.next_int(cnt)];\n        reverse(path.begin() + i + 1, path.begin() + j + 1);\n        for (int k = i + 1; k <= j; k++) pos[path[k]] = k;\n        return true;\n    }\n    return false;\n}\n\nbool mutate_path(vector<int>& path, vector<int>& pos, XorShift64& rng) {\n    int t = rng.next_int(100);\n    if (t < 55) {\n        if (random_backbite(path, pos, rng)) return true;\n        return random_two_opt(path, pos, rng);\n    } else {\n        if (random_two_opt(path, pos, rng)) return true;\n        return random_backbite(path, pos, rng);\n    }\n}\n\nbool find_best_neighbor(\n    const vector<int>& path,\n    const vector<int>& pos,\n    const EvalInfo& ref_ev,\n    vector<int>& best_path,\n    EvalInfo& best_ev,\n    double deadline_sec,\n    bool require_improvement\n) {\n    bool found = false;\n    EvalInfo best{INF64, INT_MAX};\n\n    auto consider = [&](vector<int>& cand) {\n        EvalInfo ev;\n        orient_best_inplace(cand, ev);\n        if (require_improvement && !better_eval(ev, ref_ev)) return;\n        if (!found || better_eval(ev, best)) {\n            found = true;\n            best = ev;\n            best_path = cand;\n        }\n    };\n\n    {\n        int ep = path[0];\n        int forbidden = path[1];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i <= 1) continue;\n            vector<int> cand = path;\n            reverse(cand.begin(), cand.begin() + i);\n            consider(cand);\n        }\n    }\n\n    {\n        int ep = path[M - 1];\n        int forbidden = path[M - 2];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.end());\n            consider(cand);\n        }\n    }\n\n    for (int i = 0; i < M - 1; i++) {\n        if ((i & 31) == 0 && elapsed_sec() > deadline_sec) break;\n\n        int a = path[i];\n        int b = path[i + 1];\n        int prev = (i > 0 ? path[i - 1] : -1);\n\n        for (int u : neigh_[a]) {\n            if (u == b || u == prev) continue;\n            int j = pos[u];\n            if (j <= i + 1) continue;\n            if (i == 0 && j == M - 1) continue;\n            if (j != M - 1 && !adjmat_[b][path[j + 1]]) continue;\n\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.begin() + j + 1);\n            consider(cand);\n        }\n    }\n\n    if (!found) return false;\n    best_ev = best;\n    return true;\n}\n\nbool best_improving_move(vector<int>& path, vector<int>& pos, EvalInfo& cur_ev, double deadline_sec) {\n    vector<int> best_path;\n    EvalInfo best_ev;\n    if (!find_best_neighbor(path, pos, cur_ev, best_path, best_ev, deadline_sec, true)) return false;\n    path.swap(best_path);\n    build_pos(path, pos);\n    cur_ev = best_ev;\n    return true;\n}\n\nvoid greedy_local_opt(vector<int>& path, EvalInfo& ev, int max_steps, double deadline_sec) {\n    orient_best_inplace(path, ev);\n    vector<int> pos;\n    build_pos(path, pos);\n\n    for (int step = 0; step < max_steps; step++) {\n        if (elapsed_sec() > deadline_sec) break;\n        if (!best_improving_move(path, pos, ev, deadline_sec)) break;\n    }\n}\n\nbool propose_best_random_mutation(\n    const vector<int>& base_path,\n    const vector<int>& base_pos,\n    XorShift64& rng,\n    int samples,\n    int kick_lo,\n    int kick_hi,\n    vector<int>& best_path,\n    EvalInfo& best_ev\n) {\n    bool found = false;\n    for (int s = 0; s < samples; s++) {\n        vector<int> cand = base_path;\n        vector<int> pos = base_pos;\n        int kicks = kick_lo + rng.next_int(kick_hi - kick_lo + 1);\n        bool ok = false;\n        for (int t = 0; t < kicks; t++) ok |= mutate_path(cand, pos, rng);\n        if (!ok) continue;\n        EvalInfo ev;\n        orient_best_inplace(cand, ev);\n        if (!found || better_eval(ev, best_ev)) {\n            found = true;\n            best_ev = ev;\n            best_path.swap(cand);\n        }\n    }\n    return found;\n}\n\nbool propose_best_polished_mutation(\n    const vector<int>& base_path,\n    const vector<int>& base_pos,\n    XorShift64& rng,\n    int samples,\n    int kick_lo,\n    int kick_hi,\n    int polish_steps,\n    double deadline_sec,\n    vector<int>& best_path,\n    EvalInfo& best_ev\n) {\n    bool found = false;\n    for (int s = 0; s < samples; s++) {\n        if (elapsed_sec() > deadline_sec) break;\n        vector<int> cand = base_path;\n        vector<int> pos = base_pos;\n        int kicks = kick_lo + rng.next_int(kick_hi - kick_lo + 1);\n        bool ok = false;\n        for (int t = 0; t < kicks; t++) ok |= mutate_path(cand, pos, rng);\n        if (!ok) continue;\n        EvalInfo ev;\n        orient_best_inplace(cand, ev);\n        greedy_local_opt(cand, ev, polish_steps, deadline_sec);\n        if (!found || better_eval(ev, best_ev)) {\n            found = true;\n            best_ev = ev;\n            best_path.swap(cand);\n        }\n    }\n    return found;\n}\n\nbool propose_best_mixed_mutation(\n    const vector<int>& base_path,\n    const vector<int>& base_pos,\n    XorShift64& rng,\n    const vector<array<int, 4>>& specs, // {samples, kick_lo, kick_hi, polish_steps}\n    double deadline_sec,\n    vector<int>& best_path,\n    EvalInfo& best_ev\n) {\n    bool found = false;\n    for (auto sp : specs) {\n        int samples = sp[0];\n        int kick_lo = sp[1];\n        int kick_hi = sp[2];\n        int polish = sp[3];\n        for (int s = 0; s < samples; s++) {\n            if (elapsed_sec() > deadline_sec) return found;\n            vector<int> cand = base_path;\n            vector<int> pos = base_pos;\n            int kicks = kick_lo + (kick_hi == kick_lo ? 0 : rng.next_int(kick_hi - kick_lo + 1));\n            bool ok = false;\n            for (int t = 0; t < kicks; t++) ok |= mutate_path(cand, pos, rng);\n            if (!ok) continue;\n            EvalInfo ev;\n            orient_best_inplace(cand, ev);\n            if (polish > 0) greedy_local_opt(cand, ev, polish, deadline_sec);\n            if (!found || better_eval(ev, best_ev)) {\n                found = true;\n                best_ev = ev;\n                best_path.swap(cand);\n            }\n        }\n    }\n    return found;\n}\n\nvoid collect_backbite_variants(const vector<int>& path, const vector<int>& pos, vector<vector<int>>& out) {\n    out.clear();\n\n    {\n        int ep = path[0];\n        int forbidden = path[1];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i <= 1) continue;\n            vector<int> cand = path;\n            reverse(cand.begin(), cand.begin() + i);\n            out.push_back(move(cand));\n        }\n    }\n    {\n        int ep = path[M - 1];\n        int forbidden = path[M - 2];\n        for (int u : neigh_[ep]) {\n            if (u == forbidden) continue;\n            int i = pos[u];\n            if (i >= M - 2) continue;\n            vector<int> cand = path;\n            reverse(cand.begin() + i + 1, cand.end());\n            out.push_back(move(cand));\n        }\n    }\n}\n\nbool double_backbite_intensify(vector<int>& path, EvalInfo& ev, double deadline_sec) {\n    vector<int> pos;\n    build_pos(path, pos);\n\n    vector<vector<int>> firsts;\n    collect_backbite_variants(path, pos, firsts);\n\n    bool improved = false;\n    EvalInfo best_ev = ev;\n    vector<int> best_path = path;\n\n    for (auto cand1 : firsts) {\n        if (elapsed_sec() > deadline_sec) break;\n\n        EvalInfo ev1;\n        orient_best_inplace(cand1, ev1);\n        greedy_local_opt(cand1, ev1, 6, deadline_sec);\n        if (better_eval(ev1, best_ev)) {\n            best_ev = ev1;\n            best_path = cand1;\n            improved = true;\n        }\n\n        if (elapsed_sec() > deadline_sec) break;\n\n        vector<int> pos1;\n        build_pos(cand1, pos1);\n        vector<vector<int>> seconds;\n        collect_backbite_variants(cand1, pos1, seconds);\n\n        for (auto cand2 : seconds) {\n            if (elapsed_sec() > deadline_sec) break;\n            EvalInfo ev2;\n            orient_best_inplace(cand2, ev2);\n            greedy_local_opt(cand2, ev2, 6, deadline_sec);\n            if (better_eval(ev2, best_ev)) {\n                best_ev = ev2;\n                best_path = cand2;\n                improved = true;\n            }\n        }\n    }\n\n    if (improved) {\n        path.swap(best_path);\n        ev = best_ev;\n    }\n    return improved;\n}\n\nchar dir_between(int a, int b) {\n    if (rr_[b] == rr_[a] + 1 && cc_[b] == cc_[a]) return 'D';\n    if (rr_[b] == rr_[a] - 1 && cc_[b] == cc_[a]) return 'U';\n    if (rr_[b] == rr_[a] && cc_[b] == cc_[a] + 1) return 'R';\n    return 'L';\n}\n\nvoid move_manhattan(int& cr, int& cc, int tr, int tc, vector<string>& ans) {\n    while (cr < tr) ans.push_back(\"D\"), cr++;\n    while (cr > tr) ans.push_back(\"U\"), cr--;\n    while (cc < tc) ans.push_back(\"R\"), cc++;\n    while (cc > tc) ans.push_back(\"L\"), cc--;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    TIME_BEGIN = chrono::steady_clock::now();\n\n    cin >> N;\n    M = N * N;\n\n    vector<vector<int>> h(N, vector<int>(N));\n    H1.assign(M, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> h[i][j];\n            int id = i * N + j;\n            H1[id] = h[i][j];\n            BASE_COST += llabs((long long)h[i][j]);\n        }\n    }\n\n    if (BASE_COST == 0) return 0;\n\n    for (int id = 0; id < M; id++) {\n        rr_[id] = id / N;\n        cc_[id] = id % N;\n        dist0_[id] = rr_[id] + cc_[id];\n    }\n    for (int a = 0; a < M; a++) {\n        neigh_[a].clear();\n        for (int b = 0; b < M; b++) {\n            distmat_[a][b] = abs(rr_[a] - rr_[b]) + abs(cc_[a] - cc_[b]);\n            adjmat_[a][b] = (distmat_[a][b] == 1);\n        }\n        int r = rr_[a], c = cc_[a];\n        if (r > 0) neigh_[a].push_back((r - 1) * N + c);\n        if (r + 1 < N) neigh_[a].push_back((r + 1) * N + c);\n        if (c > 0) neigh_[a].push_back(r * N + (c - 1));\n        if (c + 1 < N) neigh_[a].push_back(r * N + (c + 1));\n    }\n\n    uint64_t seed = 0x9e3779b97f4a7c15ull;\n    for (int i = 0; i < M; i++) {\n        seed ^= (uint64_t)(H1[i] + 128 + 1009 * i);\n        seed ^= seed << 13;\n        seed ^= seed >> 7;\n        seed ^= seed << 17;\n    }\n    XorShift64 rng(seed);\n\n    vector<Point> cyc0 = make_base_cycle(N);\n    vector<Point> snake0 = make_row_snake(N);\n    vector<Point> spiral0 = make_spiral(N);\n    vector<Point> gilbert0 = make_gilbert(N);\n\n    vector<vector<Point>> base_cycles;\n    vector<vector<Point>> base_paths;\n\n    if (validate_order(cyc0, N, true)) base_cycles.push_back(cyc0);\n    if (validate_order(snake0, N, false)) base_paths.push_back(snake0);\n    if (validate_order(spiral0, N, false)) base_paths.push_back(spiral0);\n    if (validate_order(gilbert0, N, false)) base_paths.push_back(gilbert0);\n\n    vector<Candidate> pool;\n    pool.reserve(128);\n\n    for (auto& bc : base_cycles) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto ordp = transform_order(bc, sym, rev, N);\n                if (!validate_order(ordp, N, true)) continue;\n                auto ids = points_to_ids(ordp);\n                auto [ev, st] = eval_cycle_best_shift(ids);\n                rotate(ids.begin(), ids.begin() + st, ids.end());\n                Candidate c{ev.cost, ev.borrow, move(ids), 0};\n                c.hs = hash_order(c.path);\n                pool.push_back(move(c));\n            }\n        }\n    }\n\n    for (auto& bp : base_paths) {\n        for (int sym = 0; sym < 8; sym++) {\n            for (int rev = 0; rev < 2; rev++) {\n                auto ordp = transform_order(bp, sym, rev, N);\n                if (!validate_order(ordp, N, false)) continue;\n                auto ids = points_to_ids(ordp);\n                EvalInfo ev;\n                orient_best_inplace(ids, ev);\n                Candidate c{ev.cost, ev.borrow, move(ids), 0};\n                c.hs = hash_order(c.path);\n                pool.push_back(move(c));\n            }\n        }\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.cost != b.cost) return a.cost < b.cost;\n        return a.borrow < b.borrow;\n    });\n\n    Candidate global_best = pool[0];\n    vector<Candidate> elites;\n    const int ELITE_MAX = 16;\n\n    auto push_elite = [&](const vector<int>& path, const EvalInfo& ev) {\n        uint64_t hs = hash_order(path);\n        for (auto& e : elites) {\n            if (e.hs == hs) return;\n        }\n        elites.push_back({ev.cost, ev.borrow, path, hs});\n        sort(elites.begin(), elites.end(), [](const Candidate& a, const Candidate& b) {\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.borrow < b.borrow;\n        });\n        if ((int)elites.size() > ELITE_MAX) elites.resize(ELITE_MAX);\n    };\n\n    auto update_global = [&](const vector<int>& path, const EvalInfo& ev) {\n        EvalInfo cur{global_best.cost, global_best.borrow};\n        if (better_eval(ev, cur)) {\n            global_best.cost = ev.cost;\n            global_best.borrow = ev.borrow;\n            global_best.path = path;\n            global_best.hs = hash_order(path);\n        }\n        push_elite(path, ev);\n    };\n\n    for (int i = 0; i < min<int>((int)pool.size(), 12); i++) {\n        EvalInfo ev{pool[i].cost, pool[i].borrow};\n        push_elite(pool[i].path, ev);\n    }\n\n    vector<vector<int>> seeds;\n    {\n        unordered_set<uint64_t> used;\n        used.reserve(512);\n        for (auto& cand : pool) {\n            if (used.insert(cand.hs).second) {\n                seeds.push_back(cand.path);\n                if ((int)seeds.size() >= 12) break;\n            }\n        }\n        for (int idx : {16, 24, 36, 48}) {\n            if (idx < (int)pool.size()) {\n                if (used.insert(pool[idx].hs).second) seeds.push_back(pool[idx].path);\n            }\n        }\n        if (seeds.empty()) seeds.push_back(global_best.path);\n    }\n\n    const double TOTAL_TL = 1.92;\n    const double SA_END = 1.54;\n\n    for (int i = 0; i < (int)seeds.size() && i < 6; i++) {\n        if (elapsed_sec() > 0.24) break;\n        EvalInfo ev;\n        greedy_local_opt(seeds[i], ev, 6, 0.24);\n        update_global(seeds[i], ev);\n    }\n\n    auto choose_elite_path = [&]() -> const vector<int>& {\n        if (elites.empty()) return global_best.path;\n        int lim = min<int>(8, elites.size());\n        double x = rng.next_double();\n        int idx = min(lim - 1, (int)(x * x * lim));\n        return elites[idx].path;\n    };\n\n    auto make_state = [&](const vector<int>& base_path, int perturb_steps) -> State {\n        State st;\n        st.path = base_path;\n        build_pos(st.path, st.pos);\n\n        vector<int> bestp = st.path;\n        EvalInfo bestev;\n        orient_best_inplace(bestp, bestev);\n\n        int tries = (perturb_steps == 0 ? 1 : 2);\n        for (int z = 0; z < tries; z++) {\n            vector<int> cand = base_path;\n            vector<int> pos;\n            build_pos(cand, pos);\n            for (int t = 0; t < perturb_steps; t++) mutate_path(cand, pos, rng);\n            EvalInfo ev;\n            orient_best_inplace(cand, ev);\n            if (better_eval(ev, bestev)) {\n                bestp.swap(cand);\n                bestev = ev;\n            }\n        }\n        st.path.swap(bestp);\n\n        if (elapsed_sec() < 0.62) {\n            greedy_local_opt(st.path, bestev, 2, 0.62);\n        }\n\n        build_pos(st.path, st.pos);\n        st.cost = bestev.cost;\n        update_global(st.path, bestev);\n        return st;\n    };\n\n    vector<State> states;\n    for (int i = 0; i < (int)seeds.size() && i < 8; i++) {\n        states.push_back(make_state(seeds[i], 0));\n    }\n    for (int i = 0; i < (int)seeds.size() && i < 8; i++) {\n        states.push_back(make_state(seeds[i], 16 + 8 * i));\n    }\n    if (states.empty()) {\n        states.push_back(make_state(global_best.path, 0));\n    }\n\n    double next_restart = 0.34;\n\n    while (elapsed_sec() < SA_END) {\n        int idx = rng.next_int((int)states.size());\n        State& cur = states[idx];\n\n        vector<int> cand_path;\n        EvalInfo cand_ev;\n        int samples = (elapsed_sec() < SA_END * 0.70 ? 2 : 3);\n        if (!propose_best_random_mutation(cur.path, cur.pos, rng, samples, 1, 3, cand_path, cand_ev)) continue;\n\n        double frac = elapsed_sec() / SA_END;\n        double T0 = 1800.0, T1 = 10.0;\n        double temp = T0 * pow(T1 / T0, frac);\n\n        bool accept = false;\n        if (cand_ev.cost <= cur.cost) {\n            accept = true;\n        } else {\n            double prob = exp((double)(cur.cost - cand_ev.cost) / temp);\n            if (rng.next_double() < prob) accept = true;\n        }\n\n        if (accept) {\n            cur.path.swap(cand_path);\n            build_pos(cur.path, cur.pos);\n            cur.cost = cand_ev.cost;\n\n            EvalInfo gcur{global_best.cost, global_best.borrow};\n            if (better_eval(cand_ev, gcur) && elapsed_sec() < SA_END - 0.04) {\n                greedy_local_opt(cur.path, cand_ev, 2, SA_END - 0.01);\n                build_pos(cur.path, cur.pos);\n                cur.cost = cand_ev.cost;\n            }\n            update_global(cur.path, cand_ev);\n        }\n\n        if (elapsed_sec() >= next_restart && elapsed_sec() < SA_END - 0.05) {\n            int worst = 0;\n            for (int i = 1; i < (int)states.size(); i++) {\n                if (states[i].cost > states[worst].cost) worst = i;\n            }\n\n            const vector<int>& base = choose_elite_path();\n            State best_state = make_state(base, 20 + rng.next_int(20));\n            if (elapsed_sec() < SA_END - 0.02) {\n                State alt_state = make_state(base, 20 + rng.next_int(20));\n                if (alt_state.cost < best_state.cost) best_state = move(alt_state);\n            }\n            states[worst] = move(best_state);\n            next_restart += 0.34;\n        }\n    }\n\n    for (int i = 0; i < (int)elites.size() && i < 5; i++) {\n        if (elapsed_sec() > 1.70) break;\n        vector<int> cand = elites[i].path;\n        EvalInfo ev{elites[i].cost, elites[i].borrow};\n        greedy_local_opt(cand, ev, 20, 1.70);\n        update_global(cand, ev);\n    }\n\n    while (elapsed_sec() < 1.83) {\n        const vector<int>& base = choose_elite_path();\n        vector<int> pos0;\n        build_pos(base, pos0);\n\n        vector<int> cand;\n        EvalInfo ev;\n        vector<array<int, 4>> specs = {\n            {2, 2, 6, 2},\n            {1, 7, 14, 1},\n        };\n        if (!propose_best_mixed_mutation(base, pos0, rng, specs, 1.83, cand, ev)) break;\n\n        greedy_local_opt(cand, ev, 8, 1.83);\n        update_global(cand, ev);\n    }\n\n    {\n        int lim = min<int>(3, elites.size());\n        for (int i = 0; i < lim; i++) {\n            if (elapsed_sec() > 1.885) break;\n            vector<int> pos0;\n            build_pos(elites[i].path, pos0);\n\n            vector<int> cand;\n            EvalInfo ev;\n            vector<array<int, 4>> specs = {\n                {2, 2, 6, 2},\n                {1, 5, 10, 2},\n            };\n            if (propose_best_mixed_mutation(elites[i].path, pos0, rng, specs, 1.865, cand, ev)) {\n                greedy_local_opt(cand, ev, 6, 1.875);\n                double_backbite_intensify(cand, ev, 1.885);\n                update_global(cand, ev);\n            } else {\n                cand = elites[i].path;\n                ev = {elites[i].cost, elites[i].borrow};\n                greedy_local_opt(cand, ev, 8, 1.865);\n                double_backbite_intensify(cand, ev, 1.885);\n                update_global(cand, ev);\n            }\n        }\n    }\n\n    {\n        vector<int> cur = global_best.path;\n        EvalInfo cur_ev{global_best.cost, global_best.borrow};\n        greedy_local_opt(cur, cur_ev, 12, 1.895);\n        update_global(cur, cur_ev);\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(16);\n        seen.insert(hash_order(cur));\n\n        for (int step = 0; step < 2 && elapsed_sec() < 1.905; step++) {\n            vector<int> pos;\n            build_pos(cur, pos);\n\n            vector<int> nxt;\n            EvalInfo nxt_ev;\n            if (!find_best_neighbor(cur, pos, cur_ev, nxt, nxt_ev, 1.905, false)) break;\n\n            uint64_t hs = hash_order(nxt);\n            if (!seen.insert(hs).second) break;\n\n            greedy_local_opt(nxt, nxt_ev, 8, 1.905);\n            update_global(nxt, nxt_ev);\n\n            cur.swap(nxt);\n            cur_ev = nxt_ev;\n        }\n    }\n\n    {\n        vector<int> cand = global_best.path;\n        EvalInfo ev{global_best.cost, global_best.borrow};\n        greedy_local_opt(cand, ev, 40, TOTAL_TL - 0.005);\n        update_global(cand, ev);\n    }\n\n    vector<string> ans;\n    ans.reserve(3200);\n\n    int cr = 0, cc = 0;\n    int start_id = global_best.path.front();\n    move_manhattan(cr, cc, rr_[start_id], cc_[start_id], ans);\n\n    if (global_best.borrow > 0) {\n        ans.push_back(\"+\" + to_string(global_best.borrow));\n    }\n\n    for (int i = 0; i < M; i++) {\n        int id = global_best.path[i];\n        int v = H1[id];\n        if (v > 0) ans.push_back(\"+\" + to_string(v));\n        else if (v < 0) ans.push_back(\"-\" + to_string(-v));\n\n        if (i + 1 < M) {\n            char d = dir_between(global_best.path[i], global_best.path[i + 1]);\n            ans.push_back(string(1, d));\n        }\n    }\n\n    if (global_best.borrow > 0) {\n        int end_id = global_best.path.back();\n        cr = rr_[end_id];\n        cc = cc_[end_id];\n        move_manhattan(cr, cc, rr_[start_id], cc_[start_id], ans);\n        ans.push_back(\"-\" + to_string(global_best.borrow));\n    }\n\n    for (auto& s : ans) cout << s << '\\n';\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct Seed {\n    array<int, 15> x{};\n    int value = 0;\n};\n\nclass Solver {\npublic:\n    static constexpr int MAXSUM = 1500;\n\n    int N, M, T;\n    int S, P;\n\n    vector<Seed> seeds;\n\n    vector<vector<int>> adj;\n    vector<pair<int, int>> edges;\n    vector<int> deg;\n    vector<int> posOrder;\n    vector<int> blackPos, whitePos;\n\n    mt19937_64 rng;\n\n    // per-turn stats\n    array<double, 15> rareW{};\n    array<double, 61> powHalf{};\n    vector<ll> weightedSeedValue;\n    vector<vector<int>> evalQ;\n\n    // per-turn late-game cache\n    vector<array<float, MAXSUM + 1>> pairCDF;\n\n    Solver(int N_, int M_, int T_)\n        : N(N_), M(M_), T(T_), S(2 * N_ * (N_ - 1)), P(N_ * N_),\n          rng((uint64_t)chrono::steady_clock::now().time_since_epoch().count()) {\n        buildGrid();\n        powHalf[0] = 1.0;\n        for (int i = 1; i <= 60; i++) powHalf[i] = powHalf[i - 1] * 0.5;\n    }\n\n    void buildGrid() {\n        adj.assign(P, {});\n        deg.assign(P, 0);\n        edges.clear();\n        blackPos.clear();\n        whitePos.clear();\n\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                if (((r + c) & 1) == 0) blackPos.push_back(p);\n                else whitePos.push_back(p);\n\n                if (c + 1 < N) {\n                    int q = r * N + (c + 1);\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n                if (r + 1 < N) {\n                    int q = (r + 1) * N + c;\n                    adj[p].push_back(q);\n                    adj[q].push_back(p);\n                    edges.push_back({p, q});\n                }\n            }\n        }\n        for (int p = 0; p < P; p++) deg[p] = (int)adj[p].size();\n\n        vector<pair<array<int, 5>, int>> ord;\n        ord.reserve(P);\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int p = r * N + c;\n                int dist = abs(2 * r - (N - 1)) + abs(2 * c - (N - 1));\n                ord.push_back({{dist, -deg[p], ((r + c) & 1), r, c}, p});\n            }\n        }\n        sort(ord.begin(), ord.end());\n        posOrder.clear();\n        for (auto &e : ord) posOrder.push_back(e.second);\n    }\n\n    bool readSeeds() {\n        seeds.assign(S, Seed());\n        for (int i = 0; i < S; i++) {\n            int sum = 0;\n            for (int j = 0; j < M; j++) {\n                if (!(cin >> seeds[i].x[j])) return false;\n                sum += seeds[i].x[j];\n            }\n            seeds[i].value = sum;\n        }\n        return true;\n    }\n\n    void buildTurnStatistics(int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n\n        array<int, 15> best1{}, best2{}, cntNear{};\n        for (int l = 0; l < M; l++) {\n            int mx1 = -1, mx2 = -1;\n            for (int i = 0; i < S; i++) {\n                int v = seeds[i].x[l];\n                if (v > mx1) {\n                    mx2 = mx1;\n                    mx1 = v;\n                } else if (v > mx2) {\n                    mx2 = v;\n                }\n            }\n            int cnt = 0;\n            for (int i = 0; i < S; i++) {\n                if (seeds[i].x[l] >= mx1 - 1) cnt++;\n            }\n            best1[l] = mx1;\n            best2[l] = max(0, mx2);\n            cntNear[l] = max(1, cnt);\n        }\n\n        double sumW = 0.0;\n        for (int l = 0; l < M; l++) {\n            double scarcity = 1.0 / cntNear[l];\n            double gapRatio = (double)(best1[l] - best2[l]) / max(1, best1[l]);\n            double w = 1.0 + (0.55 * scarcity + 0.90 * gapRatio) * (0.25 + 1.35 * g);\n            rareW[l] = w;\n            sumW += w;\n        }\n        double norm = (double)M / sumW;\n        for (int l = 0; l < M; l++) rareW[l] *= norm;\n\n        weightedSeedValue.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            double s = 0.0;\n            for (int l = 0; l < M; l++) s += rareW[l] * seeds[i].x[l];\n            weightedSeedValue[i] = (ll)llround(100.0 * s);\n        }\n\n        evalQ.assign(S, vector<int>(S, 0));\n        double betaEval = 1.65 + 0.20 * (1.0 - g);\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0;\n                double mean = 0.5 * (seeds[i].value + seeds[j].value);\n                double diff2 = 0.0;\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    opt += max(a, b);\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n                }\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + betaEval * sigma);\n                int v = (int)llround(q * 100.0);\n                evalQ[i][j] = evalQ[j][i] = v;\n            }\n        }\n    }\n\n    vector<vector<ll>> makeScoreMatrix(int scheme, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n        double alphaBalanced = 0.25 + 0.45 * g;\n        double alphaRare = 0.35 + 0.40 * g;\n        double beta = 1.45 + 0.30 * (1.0 - g);\n\n        vector<vector<ll>> sc(S, vector<ll>(S, 0));\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double opt = 0.0, mean = 0.5 * (seeds[i].value + seeds[j].value), diff2 = 0.0;\n                double optw = 0.0, meanw = 0.0, diffw2 = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    int mx = max(a, b);\n\n                    opt += mx;\n                    double d = (double)a - (double)b;\n                    diff2 += d * d;\n\n                    optw += rareW[l] * mx;\n                    meanw += 0.5 * rareW[l] * (a + b);\n                    double dw = rareW[l] * d;\n                    diffw2 += dw * dw;\n                }\n\n                double sigma = 0.5 * sqrt(diff2);\n                double q = min(opt, mean + beta * sigma);\n\n                double sigmaw = 0.5 * sqrt(diffw2);\n                double qw = min(optw, meanw + beta * sigmaw);\n\n                double val = 0.0;\n                switch (scheme) {\n                    case 0: val = alphaBalanced * opt + (1.0 - alphaBalanced) * q; break;\n                    case 1: val = alphaRare * optw + (1.0 - alphaRare) * qw; break;\n                    case 2: val = opt; break;\n                    case 3: val = q; break;\n                    case 4: val = qw; break;\n                    case 5: val = optw; break;\n                    case 6: val = q * q / 1000.0; break;\n                    default: val = q; break;\n                }\n\n                ll iv = (ll)llround(val * 100.0);\n                sc[i][j] = sc[j][i] = iv;\n            }\n        }\n        return sc;\n    }\n\n    vector<ll> computeIndividualPotential(const vector<vector<ll>>& sc, int remTurns) {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n        int K = min(5, S - 1);\n\n        vector<ll> ind(S, 0);\n        vector<ll> tmp;\n        tmp.reserve(S - 1);\n\n        for (int i = 0; i < S; i++) {\n            tmp.clear();\n            for (int j = 0; j < S; j++) {\n                if (i == j) continue;\n                tmp.push_back(sc[i][j]);\n            }\n            if (K < (int)tmp.size()) {\n                nth_element(tmp.begin(), tmp.begin() + K, tmp.end(), greater<ll>());\n            }\n            ll sumTop = 0;\n            for (int k = 0; k < K; k++) sumTop += tmp[k];\n\n            ll bias = 25LL * seeds[i].value + (ll)llround((12.0 + 18.0 * g) * (weightedSeedValue[i] / 100.0));\n            ind[i] = sumTop / K + bias;\n        }\n        return ind;\n    }\n\n    vector<int> initAssignment(const vector<vector<ll>>& sc, const vector<ll>& ind, int mode, int noiseScale) {\n        vector<int> assign(P, -1);\n        vector<char> used(S, false);\n\n        if (mode == 1) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (seeds[a].value != seeds[b].value) return seeds[a].value > seeds[b].value;\n                return weightedSeedValue[a] > weightedSeedValue[b];\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        if (mode == 2) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (ind[a] != ind[b]) return ind[a] > ind[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        if (mode == 3) {\n            array<int, 15> bestNow{};\n            bestNow.fill(0);\n\n            for (int idx = 0; idx < P; idx++) {\n                ll bestScore = LLONG_MIN;\n                int bestSeed = -1;\n\n                for (int s = 0; s < S; s++) if (!used[s]) {\n                    ll gain = 0;\n                    for (int l = 0; l < M; l++) {\n                        int v = seeds[s].x[l];\n                        if (v > bestNow[l]) {\n                            gain += (ll)llround(100.0 * rareW[l] * (v - bestNow[l]));\n                        }\n                    }\n                    ll score = gain + weightedSeedValue[s] / 6 + 20LL * seeds[s].value;\n                    if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                    if (score > bestScore || (score == bestScore && (rng() & 1ULL))) {\n                        bestScore = score;\n                        bestSeed = s;\n                    }\n                }\n\n                assign[posOrder[idx]] = bestSeed;\n                used[bestSeed] = true;\n                for (int l = 0; l < M; l++) bestNow[l] = max(bestNow[l], seeds[bestSeed].x[l]);\n            }\n            return assign;\n        }\n\n        if (mode == 4) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (weightedSeedValue[a] != weightedSeedValue[b]) return weightedSeedValue[a] > weightedSeedValue[b];\n                return seeds[a].value > seeds[b].value;\n            });\n            for (int k = 0; k < P; k++) {\n                assign[posOrder[k]] = ids[k];\n                used[ids[k]] = true;\n            }\n            return assign;\n        }\n\n        // greedy\n        for (int p : posOrder) {\n            int fixedCnt = 0;\n            for (int nb : adj[p]) if (assign[nb] != -1) fixedCnt++;\n\n            ll bestSc = LLONG_MIN;\n            int bestSeed = -1;\n\n            for (int s = 0; s < S; s++) if (!used[s]) {\n                ll score = 1LL * (deg[p] - fixedCnt) * ind[s];\n                for (int nb : adj[p]) {\n                    if (assign[nb] != -1) score += sc[s][assign[nb]];\n                }\n                if (noiseScale > 0) score += (ll)(rng() % (noiseScale + 1));\n\n                if (score > bestSc || (score == bestSc && (rng() & 1ULL))) {\n                    bestSc = score;\n                    bestSeed = s;\n                }\n            }\n\n            assign[p] = bestSeed;\n            used[bestSeed] = true;\n        }\n\n        return assign;\n    }\n\n    ll calcObjective(const vector<int>& assign, const vector<vector<ll>>& sc) const {\n        ll res = 0;\n        for (auto [u, v] : edges) res += sc[assign[u]][assign[v]];\n        return res;\n    }\n\n    vector<int> hungarianMax(const vector<vector<ll>>& a) const {\n        int n = (int)a.size();\n        int m = (int)a[0].size();\n        const ll INF = (1LL << 60);\n\n        vector<ll> u(n + 1), v(m + 1);\n        vector<int> p(m + 1), way(m + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            vector<ll> minv(m + 1, INF);\n            vector<char> used(m + 1, false);\n            int j0 = 0;\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0], j1 = 0;\n                ll delta = INF;\n\n                for (int j = 1; j <= m; j++) if (!used[j]) {\n                    ll cur = -a[i0 - 1][j - 1] - u[i0] - v[j];\n                    if (cur < minv[j]) {\n                        minv[j] = cur;\n                        way[j] = j0;\n                    }\n                    if (minv[j] < delta) {\n                        delta = minv[j];\n                        j1 = j;\n                    }\n                }\n\n                for (int j = 0; j <= m; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while (p[j0] != 0);\n\n            do {\n                int j1 = way[j0];\n                p[j0] = p[j1];\n                j0 = j1;\n            } while (j0);\n        }\n\n        vector<int> ans(n, -1);\n        for (int j = 1; j <= m; j++) {\n            if (p[j] != 0) ans[p[j] - 1] = j - 1;\n        }\n        return ans;\n    }\n\n    void optimizeColor(vector<int>& assign, const vector<vector<ll>>& sc,\n                       const vector<int>& group, const vector<int>& other) {\n        vector<char> banned(S, false);\n        for (int p : other) banned[assign[p]] = true;\n\n        vector<int> cand;\n        cand.reserve(S - (int)other.size());\n        for (int s = 0; s < S; s++) if (!banned[s]) cand.push_back(s);\n\n        int n = (int)group.size();\n        int m = (int)cand.size();\n        vector<vector<ll>> benefit(n, vector<ll>(m, 0));\n\n        for (int i = 0; i < n; i++) {\n            int p = group[i];\n            for (int j = 0; j < m; j++) {\n                int s = cand[j];\n                ll b = 0;\n                for (int nb : adj[p]) b += sc[s][assign[nb]];\n                benefit[i][j] = b;\n            }\n        }\n\n        vector<int> choice = hungarianMax(benefit);\n        for (int i = 0; i < n; i++) assign[group[i]] = cand[choice[i]];\n    }\n\n    ll coordinateAscent(vector<int>& assign, const vector<vector<ll>>& sc) {\n        ll obj = calcObjective(assign, sc);\n        for (int it = 0; it < 8; it++) {\n            ll old = obj;\n            optimizeColor(assign, sc, blackPos, whitePos);\n            optimizeColor(assign, sc, whitePos, blackPos);\n            obj = calcObjective(assign, sc);\n            if (obj <= old) break;\n        }\n        return obj;\n    }\n\n    ll deltaSwap(const vector<int>& assign, const vector<vector<ll>>& sc, int p, int q) const {\n        if (p == q) return 0;\n        int a = assign[p];\n        int b = assign[q];\n        ll d = 0;\n\n        for (int nb : adj[p]) {\n            if (nb == q) continue;\n            d += sc[b][assign[nb]] - sc[a][assign[nb]];\n        }\n        for (int nb : adj[q]) {\n            if (nb == p) continue;\n            d += sc[a][assign[nb]] - sc[b][assign[nb]];\n        }\n        return d;\n    }\n\n    ll crossSwapImprove(vector<int>& assign, const vector<vector<ll>>& sc, ll obj) {\n        for (int pass = 0; pass < 6; pass++) {\n            ll bestDelta = 0;\n            int bp = -1, wq = -1;\n\n            for (int p : blackPos) {\n                for (int q : whitePos) {\n                    ll d = deltaSwap(assign, sc, p, q);\n                    if (d > bestDelta) {\n                        bestDelta = d;\n                        bp = p;\n                        wq = q;\n                    }\n                }\n            }\n            if (bestDelta <= 0) break;\n            swap(assign[bp], assign[wq]);\n            obj = coordinateAscent(assign, sc);\n        }\n        return obj;\n    }\n\n    void buildPairCDF() {\n        pairCDF.resize(S * S);\n        static double dp[MAXSUM + 1];\n        static double ndp[MAXSUM + 1];\n\n        for (int i = 0; i < S; i++) {\n            auto &selfCDF = pairCDF[i * S + i];\n            for (int s = 0; s <= MAXSUM; s++) {\n                selfCDF[s] = (s >= seeds[i].value ? 1.0f : 0.0f);\n            }\n\n            for (int j = i + 1; j < S; j++) {\n                for (int s = 0; s <= MAXSUM; s++) dp[s] = 0.0;\n                dp[0] = 1.0;\n                int curMax = 0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = seeds[i].x[l];\n                    int b = seeds[j].x[l];\n                    int nextMax = curMax + max(a, b);\n                    for (int s = 0; s <= nextMax; s++) ndp[s] = 0.0;\n\n                    if (a == b) {\n                        for (int s = 0; s <= curMax; s++) ndp[s + a] += dp[s];\n                    } else {\n                        for (int s = 0; s <= curMax; s++) {\n                            double half = 0.5 * dp[s];\n                            ndp[s + a] += half;\n                            ndp[s + b] += half;\n                        }\n                    }\n\n                    curMax = nextMax;\n                    for (int s = 0; s <= curMax; s++) dp[s] = ndp[s];\n                }\n\n                auto &cdf = pairCDF[i * S + j];\n                double cum = 0.0;\n                for (int s = 0; s <= MAXSUM; s++) {\n                    if (s <= curMax) cum += dp[s];\n                    cdf[s] = (float)cum;\n                }\n                pairCDF[j * S + i] = cdf;\n            }\n        }\n    }\n\n    double exactExpectedMaxFast(const vector<int>& assign) const {\n        static double prodCDF[MAXSUM + 1];\n        for (int s = 0; s <= MAXSUM; s++) prodCDF[s] = 1.0;\n\n        for (auto [u, v] : edges) {\n            const auto &cdf = pairCDF[assign[u] * S + assign[v]];\n            for (int s = 0; s < MAXSUM; s++) prodCDF[s] *= (double)cdf[s];\n        }\n\n        double ans = 0.0;\n        for (int s = 0; s < MAXSUM; s++) ans += 1.0 - prodCDF[s];\n        return ans;\n    }\n\n    ll evaluateCandidate(const vector<int>& assign, int remTurns, bool useExactImmediate) const {\n        double g = (double)(remTurns - 1) / max(1, T - 1);\n\n        vector<int> qvals;\n        qvals.reserve(edges.size());\n        ll totalQ = 0;\n\n        vector<array<int, 15>> virt(edges.size());\n        array<int, 15> top1{}, top2{}, top3{};\n        top1.fill(0);\n        top2.fill(0);\n        top3.fill(0);\n\n        int ei = 0;\n        for (auto [u, v] : edges) {\n            int a = assign[u], b = assign[v];\n            int q = evalQ[a][b];\n            qvals.push_back(q);\n            totalQ += q;\n\n            for (int l = 0; l < M; l++) {\n                int mv = max(seeds[a].x[l], seeds[b].x[l]);\n                virt[ei][l] = mv;\n                if (mv >= top1[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = top1[l];\n                    top1[l] = mv;\n                } else if (mv >= top2[l]) {\n                    top3[l] = top2[l];\n                    top2[l] = mv;\n                } else if (mv > top3[l]) {\n                    top3[l] = mv;\n                }\n            }\n            ei++;\n        }\n\n        sort(qvals.begin(), qvals.end(), greater<int>());\n        static const int W[10] = {100, 95, 90, 85, 80, 75, 70, 65, 60, 55};\n\n        ll weightedTop = 0;\n        for (int i = 0; i < min<int>(10, qvals.size()); i++) {\n            weightedTop += 1LL * qvals[i] * W[i];\n        }\n        weightedTop /= 100;\n\n        double c2 = 0.45 + 0.25 * g;\n        double c3 = 0.20 * g;\n        double coverage = 0.0;\n        for (int l = 0; l < M; l++) {\n            coverage += top1[l] + c2 * top2[l] + c3 * top3[l];\n        }\n\n        int bestFuture = 0;\n        if (remTurns >= 2) {\n            for (int i = 0; i < (int)virt.size(); i++) {\n                for (int j = i + 1; j < (int)virt.size(); j++) {\n                    int s = 0;\n                    for (int l = 0; l < M; l++) s += max(virt[i][l], virt[j][l]);\n                    if (s > bestFuture) bestFuture = s;\n                }\n            }\n        }\n\n        double coordExp = 0.0;\n        double coordExpRare = 0.0;\n        if (remTurns >= 2) {\n            int diffBoth[102], diffMix[102];\n            for (int l = 0; l < M; l++) {\n                memset(diffBoth, 0, sizeof(diffBoth));\n                memset(diffMix, 0, sizeof(diffMix));\n\n                for (auto [u, v] : edges) {\n                    int a = seeds[assign[u]].x[l];\n                    int b = seeds[assign[v]].x[l];\n                    if (a > b) swap(a, b);\n\n                    if (a > 0) {\n                        diffBoth[0] += 1;\n                        diffBoth[a] -= 1;\n                    }\n                    if (a < b) {\n                        diffMix[a] += 1;\n                        diffMix[b] -= 1;\n                    }\n                }\n\n                int cntBoth = 0, cntMix = 0;\n                double emax = 0.0;\n                for (int t = 0; t < 100; t++) {\n                    cntBoth += diffBoth[t];\n                    cntMix += diffMix[t];\n                    double pleq = (cntBoth > 0 ? 0.0 : powHalf[cntMix]);\n                    emax += 1.0 - pleq;\n                }\n                coordExp += emax;\n                coordExpRare += rareW[l] * emax;\n            }\n        }\n\n        ll meta = 0;\n        meta += weightedTop;\n        meta += totalQ / 50;\n        meta += (ll)llround((25.0 + 80.0 * g) * coverage);\n        if (remTurns >= 2) meta += (ll)llround((15.0 + 70.0 * g) * bestFuture);\n        if (remTurns >= 2) {\n            meta += (ll)llround((18.0 + 55.0 * g) * coordExpRare);\n            meta += (ll)llround((2.0 + 8.0 * g) * coordExp);\n            if (remTurns == 2) meta += (ll)llround(30.0 * coordExpRare);\n        }\n\n        if (useExactImmediate) {\n            double exactImm = exactExpectedMaxFast(assign);\n            double wImm = 0.0;\n            if (remTurns == 4) wImm = 70.0;\n            else if (remTurns == 3) wImm = 80.0;\n            else if (remTurns == 2) wImm = 95.0;\n            meta += (ll)llround(wImm * exactImm);\n        }\n\n        return meta;\n    }\n\n    static uint64_t splitmix64(uint64_t x) {\n        x += 0x9e3779b97f4a7c15ULL;\n        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n        return x ^ (x >> 31);\n    }\n\n    uint64_t hashAssign(const vector<int>& assign) const {\n        uint64_t h = 0x123456789abcdef0ULL;\n        for (int v : assign) {\n            h ^= splitmix64((uint64_t)v + h);\n            h = (h << 7) | (h >> 57);\n        }\n        return h;\n    }\n\n    ll localReplaceProxy(const vector<int>& assign, int p, int newSeed, int remTurns) const {\n        int oldSeed = assign[p];\n        ll d = 0;\n        for (int nb : adj[p]) d += (ll)evalQ[newSeed][assign[nb]] - evalQ[oldSeed][assign[nb]];\n        ll bonus = weightedSeedValue[newSeed] - weightedSeedValue[oldSeed];\n        if (remTurns <= 2) d += bonus / 2;\n        else d += bonus / 4;\n        return d;\n    }\n\n    ll localSwapDeltaEvalQ(const vector<int>& assign, int p, int q) const {\n        if (p == q) return 0;\n        int a = assign[p];\n        int b = assign[q];\n        ll d = 0;\n        for (int nb : adj[p]) {\n            if (nb == q) continue;\n            d += (ll)evalQ[b][assign[nb]] - evalQ[a][assign[nb]];\n        }\n        for (int nb : adj[q]) {\n            if (nb == p) continue;\n            d += (ll)evalQ[a][assign[nb]] - evalQ[b][assign[nb]];\n        }\n        return d;\n    }\n\n    struct Move {\n        ll delta;\n        int type; // 1 replace, 2 swap\n        int a, b;\n    };\n\n    static void trimTop(vector<Move>& mv, int K) {\n        if ((int)mv.size() > K) {\n            nth_element(mv.begin(), mv.begin() + K, mv.end(),\n                        [](const Move& x, const Move& y) { return x.delta > y.delta; });\n            mv.resize(K);\n        }\n        sort(mv.begin(), mv.end(),\n             [](const Move& x, const Move& y) { return x.delta > y.delta; });\n    }\n\n    vector<int> refineLateCandidate(vector<int> assign, int remTurns) {\n        if (remTurns > 3) return assign;\n\n        if (remTurns == 1) {\n            double cur = exactExpectedMaxFast(assign);\n\n            for (int pass = 0; pass < 2; pass++) {\n                vector<char> used(S, false);\n                for (int p = 0; p < P; p++) used[assign[p]] = true;\n                vector<int> unused;\n                for (int s = 0; s < S; s++) if (!used[s]) unused.push_back(s);\n\n                vector<Move> reps, swaps;\n                reps.reserve(P * (int)unused.size());\n                swaps.reserve(P * (P - 1) / 2);\n\n                for (int p = 0; p < P; p++) {\n                    for (int s : unused) {\n                        reps.push_back({localReplaceProxy(assign, p, s, remTurns), 1, p, s});\n                    }\n                }\n                for (int p = 0; p < P; p++) {\n                    for (int q = p + 1; q < P; q++) {\n                        swaps.push_back({localSwapDeltaEvalQ(assign, p, q), 2, p, q});\n                    }\n                }\n\n                trimTop(reps, 28);\n                trimTop(swaps, 20);\n\n                vector<Move> candMoves;\n                candMoves.reserve(reps.size() + swaps.size());\n                for (auto &m : reps) candMoves.push_back(m);\n                for (auto &m : swaps) candMoves.push_back(m);\n\n                double best = cur;\n                int bestIdx = -1;\n                vector<int> tmp = assign;\n\n                for (int i = 0; i < (int)candMoves.size(); i++) {\n                    auto &mv = candMoves[i];\n                    if (mv.type == 1) {\n                        int old = tmp[mv.a];\n                        tmp[mv.a] = mv.b;\n                        double val = exactExpectedMaxFast(tmp);\n                        tmp[mv.a] = old;\n                        if (val > best + 1e-12) {\n                            best = val;\n                            bestIdx = i;\n                        }\n                    } else {\n                        swap(tmp[mv.a], tmp[mv.b]);\n                        double val = exactExpectedMaxFast(tmp);\n                        swap(tmp[mv.a], tmp[mv.b]);\n                        if (val > best + 1e-12) {\n                            best = val;\n                            bestIdx = i;\n                        }\n                    }\n                }\n\n                if (bestIdx == -1) break;\n                auto &mv = candMoves[bestIdx];\n                if (mv.type == 1) assign[mv.a] = mv.b;\n                else swap(assign[mv.a], assign[mv.b]);\n                cur = best;\n            }\n            return assign;\n        }\n\n        ll cur = evaluateCandidate(assign, remTurns, true);\n\n        for (int pass = 0; pass < 2; pass++) {\n            vector<char> used(S, false);\n            for (int p = 0; p < P; p++) used[assign[p]] = true;\n            vector<int> unused;\n            for (int s = 0; s < S; s++) if (!used[s]) unused.push_back(s);\n\n            vector<Move> reps, swaps;\n            reps.reserve(P * (int)unused.size());\n            swaps.reserve(P * (P - 1) / 2);\n\n            for (int p = 0; p < P; p++) {\n                for (int s : unused) {\n                    reps.push_back({localReplaceProxy(assign, p, s, remTurns), 1, p, s});\n                }\n            }\n            for (int p = 0; p < P; p++) {\n                for (int q = p + 1; q < P; q++) {\n                    swaps.push_back({localSwapDeltaEvalQ(assign, p, q), 2, p, q});\n                }\n            }\n\n            trimTop(reps, 28);\n            trimTop(swaps, 20);\n\n            vector<Move> candMoves;\n            candMoves.reserve(reps.size() + swaps.size());\n            for (auto &m : reps) candMoves.push_back(m);\n            for (auto &m : swaps) candMoves.push_back(m);\n\n            ll best = cur;\n            int bestIdx = -1;\n            vector<int> tmp = assign;\n\n            for (int i = 0; i < (int)candMoves.size(); i++) {\n                auto &mv = candMoves[i];\n                if (mv.type == 1) {\n                    int old = tmp[mv.a];\n                    tmp[mv.a] = mv.b;\n                    ll val = evaluateCandidate(tmp, remTurns, true);\n                    tmp[mv.a] = old;\n                    if (val > best) {\n                        best = val;\n                        bestIdx = i;\n                    }\n                } else {\n                    swap(tmp[mv.a], tmp[mv.b]);\n                    ll val = evaluateCandidate(tmp, remTurns, true);\n                    swap(tmp[mv.a], tmp[mv.b]);\n                    if (val > best) {\n                        best = val;\n                        bestIdx = i;\n                    }\n                }\n            }\n\n            if (bestIdx == -1) break;\n            auto &mv = candMoves[bestIdx];\n            if (mv.type == 1) assign[mv.a] = mv.b;\n            else swap(assign[mv.a], assign[mv.b]);\n            cur = best;\n        }\n\n        return assign;\n    }\n\n    struct Candidate {\n        vector<int> assign;\n        ll meta = 0;\n        double exactImm = -1.0;\n    };\n\n    static bool betterFinal(const pair<double, ll>& a, const pair<double, ll>& b) {\n        if (a.first > b.first + 1e-12) return true;\n        if (b.first > a.first + 1e-12) return false;\n        return a.second > b.second;\n    }\n\n    vector<int> decideLayout(int turn) {\n        int remTurns = T - turn;\n        buildTurnStatistics(remTurns);\n\n        bool useExactImmediate = (remTurns <= 4);\n        if (useExactImmediate) buildPairCDF();\n\n        vector<Candidate> cands;\n        unordered_set<uint64_t> seen;\n        seen.reserve(256);\n\n        auto addCand = [&](const vector<int>& assign) {\n            uint64_t h = hashAssign(assign);\n            if (!seen.insert(h).second) return;\n            Candidate c;\n            c.assign = assign;\n            c.meta = evaluateCandidate(assign, remTurns, useExactImmediate && remTurns >= 2);\n            cands.push_back(std::move(c));\n        };\n\n        int schemeCount;\n        if (remTurns == 1) schemeCount = 7;\n        else if (remTurns <= 2) schemeCount = 7;\n        else schemeCount = 6;\n\n        for (int s = 0; s < schemeCount; s++) {\n            vector<vector<ll>> sc = makeScoreMatrix(s, remTurns);\n            vector<ll> ind = computeIndividualPotential(sc, remTurns);\n\n            vector<pair<int, int>> starts = {\n                {0, 0},\n                {1, 0},\n                {2, 0},\n                {3, 0},\n                {4, 0},\n                {0, 15000}\n            };\n\n            if (remTurns <= 2) {\n                starts.push_back({0, 30000});\n                starts.push_back({3, 8000});\n            } else if (remTurns <= 4) {\n                starts.push_back({0, 25000});\n            }\n\n            for (auto [mode, noise] : starts) {\n                vector<int> assign = initAssignment(sc, ind, mode, noise);\n                ll obj = coordinateAscent(assign, sc);\n                obj = crossSwapImprove(assign, sc, obj);\n                (void)obj;\n                addCand(assign);\n            }\n        }\n\n        if (remTurns == 1) {\n            for (auto &c : cands) c.exactImm = exactExpectedMaxFast(c.assign);\n\n            vector<int> ord(cands.size());\n            iota(ord.begin(), ord.end(), 0);\n            sort(ord.begin(), ord.end(), [&](int a, int b) {\n                if (fabs(cands[a].exactImm - cands[b].exactImm) > 1e-12) return cands[a].exactImm > cands[b].exactImm;\n                return cands[a].meta > cands[b].meta;\n            });\n\n            int L = min(6, (int)ord.size());\n            pair<double, ll> bestScore = {-1e100, LLONG_MIN};\n            vector<int> bestAssign = cands[ord[0]].assign;\n\n            for (int k = 0; k < L; k++) {\n                vector<int> refined = refineLateCandidate(cands[ord[k]].assign, 1);\n                double ex = exactExpectedMaxFast(refined);\n                ll meta = evaluateCandidate(refined, 1, false);\n                pair<double, ll> cur = {ex, meta};\n                if (betterFinal(cur, bestScore)) {\n                    bestScore = cur;\n                    bestAssign = refined;\n                }\n            }\n            return bestAssign;\n        }\n\n        sort(cands.begin(), cands.end(), [&](const Candidate& a, const Candidate& b) {\n            return a.meta > b.meta;\n        });\n\n        if (remTurns <= 3) {\n            for (auto &c : cands) c.exactImm = exactExpectedMaxFast(c.assign);\n\n            vector<int> ordMeta(cands.size()), ordExact(cands.size());\n            iota(ordMeta.begin(), ordMeta.end(), 0);\n            iota(ordExact.begin(), ordExact.end(), 0);\n\n            sort(ordMeta.begin(), ordMeta.end(), [&](int a, int b) {\n                return cands[a].meta > cands[b].meta;\n            });\n            sort(ordExact.begin(), ordExact.end(), [&](int a, int b) {\n                if (fabs(cands[a].exactImm - cands[b].exactImm) > 1e-12) return cands[a].exactImm > cands[b].exactImm;\n                return cands[a].meta > cands[b].meta;\n            });\n\n            vector<int> chosen;\n            vector<char> mark(cands.size(), 0);\n\n            int topMeta = (remTurns == 2 ? 4 : 3);\n            int topExact = 2;\n\n            for (int i = 0; i < min(topMeta, (int)ordMeta.size()); i++) {\n                int id = ordMeta[i];\n                if (!mark[id]) {\n                    mark[id] = 1;\n                    chosen.push_back(id);\n                }\n            }\n            for (int i = 0; i < min(topExact, (int)ordExact.size()); i++) {\n                int id = ordExact[i];\n                if (!mark[id]) {\n                    mark[id] = 1;\n                    chosen.push_back(id);\n                }\n            }\n\n            ll bestMeta = LLONG_MIN;\n            double bestEx = -1e100;\n            vector<int> bestAssign = cands[chosen[0]].assign;\n\n            for (int id : chosen) {\n                vector<int> refined = refineLateCandidate(cands[id].assign, remTurns);\n                ll meta = evaluateCandidate(refined, remTurns, true);\n                double ex = exactExpectedMaxFast(refined);\n                if (meta > bestMeta || (meta == bestMeta && ex > bestEx + 1e-12)) {\n                    bestMeta = meta;\n                    bestEx = ex;\n                    bestAssign = refined;\n                }\n            }\n            return bestAssign;\n        }\n\n        return cands[0].assign;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    if (!(cin >> N >> M >> T)) return 0;\n\n    Solver solver(N, M, T);\n    if (!solver.readSeeds()) return 0;\n\n    for (int t = 0; t < T; t++) {\n        vector<int> assign = solver.decideLayout(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << assign[i * N + j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        if (!solver.readSeeds()) return 0;\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct Block {\n    bool pickup;\n    vector<int> ids;\n    vector<int> order;\n    long long moveCost = 0;\n    Pt endPt{0, 0};\n};\n\nstruct Plan {\n    int startIdx = 0;\n    int h = 1;\n    long long cost = (1LL << 60);\n    string name;\n    vector<Block> blocks;\n};\n\nstruct BlockSolution {\n    long long moveCost = (1LL << 60);\n    long long score = (1LL << 60);\n    vector<int> order;\n    Pt endPt{0, 0};\n};\n\nstruct ExecResult {\n    long long cost = (1LL << 60);\n    vector<string> ops;\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double ms() const {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - st).count();\n    }\n    bool over(double limit_ms) const {\n        return ms() >= limit_ms;\n    }\n};\n\nstatic constexpr long long INF64 = (1LL << 60);\nstatic constexpr int INF = 1e9;\n\nint N, M, Vcap;\nvector<Pt> src, dst;\nint Qm;\n\nvector<vector<unsigned char>> SS, ST, TS, TT;\nvector<vector<int>> srcIdAt, dstIdAt;\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nstatic inline int dist_by_type(bool curIsSource, int curIdx, bool toSource, int toIdx) {\n    if (curIsSource) {\n        return toSource ? (int)SS[curIdx][toIdx] : (int)ST[curIdx][toIdx];\n    } else {\n        return toSource ? (int)TS[curIdx][toIdx] : (int)TT[curIdx][toIdx];\n    }\n}\n\nvector<int> make_start_candidates() {\n    vector<int> cand;\n    vector<char> used(Qm, false);\n\n    auto add = [&](int idx) {\n        if (0 <= idx && idx < Qm && !used[idx]) {\n            used[idx] = true;\n            cand.push_back(idx);\n        }\n    };\n\n    const int ALL_START_THRESHOLD = 300;\n    if (Qm <= ALL_START_THRESHOLD) {\n        for (int i = 0; i < Qm; i++) add(i);\n        return cand;\n    }\n\n    int minX = 0, maxX = 0, minY = 0, maxY = 0;\n    int minS = 0, maxS = 0, minD = 0, maxD = 0;\n    for (int i = 1; i < Qm; i++) {\n        if (src[i].x < src[minX].x) minX = i;\n        if (src[i].x > src[maxX].x) maxX = i;\n        if (src[i].y < src[minY].y) minY = i;\n        if (src[i].y > src[maxY].y) maxY = i;\n        if (src[i].x + src[i].y < src[minS].x + src[minS].y) minS = i;\n        if (src[i].x + src[i].y > src[maxS].x + src[maxS].y) maxS = i;\n        if (src[i].x - src[i].y < src[minD].x - src[minD].y) minD = i;\n        if (src[i].x - src[i].y > src[maxD].x - src[maxD].y) maxD = i;\n    }\n    add(minX); add(maxX); add(minY); add(maxY);\n    add(minS); add(maxS); add(minD); add(maxD);\n\n    vector<Pt> corners = {{0,0}, {0,N-1}, {N-1,0}, {N-1,N-1}};\n    for (auto c : corners) {\n        int best = 0, bestd = manhattan(src[0], c);\n        for (int i = 1; i < Qm; i++) {\n            int d = manhattan(src[i], c);\n            if (d < bestd) bestd = d, best = i;\n        }\n        add(best);\n    }\n\n    Pt center{N / 2, N / 2};\n    {\n        int best = 0, bestd = manhattan(src[0], center);\n        for (int i = 1; i < Qm; i++) {\n            int d = manhattan(src[i], center);\n            if (d < bestd) bestd = d, best = i;\n        }\n        add(best);\n    }\n\n    double cx = 0, cy = 0;\n    for (auto &p : src) cx += p.x, cy += p.y;\n    cx /= Qm;\n    cy /= Qm;\n\n    int nearC = 0, farC = 0;\n    double bestNear = 1e100, bestFar = -1.0;\n    for (int i = 0; i < Qm; i++) {\n        double dx = src[i].x - cx;\n        double dy = src[i].y - cy;\n        double v = dx * dx + dy * dy;\n        if (v < bestNear) bestNear = v, nearC = i;\n        if (v > bestFar) bestFar = v, farC = i;\n    }\n    add(nearC);\n    add(farC);\n\n    vector<int> ord(Qm);\n    iota(ord.begin(), ord.end(), 0);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int va = src[a].x + src[a].y;\n        int vb = src[b].x + src[b].y;\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    add(ord[0]);\n    add(ord[Qm / 4]);\n    add(ord[Qm / 2]);\n    add(ord[(3 * Qm) / 4]);\n    add(ord[Qm - 1]);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        int va = src[a].x - src[a].y;\n        int vb = src[b].x - src[b].y;\n        if (va != vb) return va < vb;\n        return a < b;\n    });\n    add(ord[0]);\n    add(ord[Qm / 4]);\n    add(ord[Qm / 2]);\n    add(ord[(3 * Qm) / 4]);\n    add(ord[Qm - 1]);\n\n    if (cand.empty()) add(0);\n    return cand;\n}\n\nlong long rough_simulate(int h, int startIdx) {\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    long long cost = 2;\n    bool curIsSource = true;\n    int curIdx = startIdx;\n    int load = 1;\n\n    while (!remS.empty() || load > 0) {\n        while (load < h && !remS.empty()) {\n            int bestPos = -1, bestId = -1, bestDist = INF;\n            if (curIsSource) {\n                const auto& row = SS[curIdx];\n                for (int pos = 0; pos < (int)remS.size(); pos++) {\n                    int id = remS[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            } else {\n                const auto& row = TS[curIdx];\n                for (int pos = 0; pos < (int)remS.size(); pos++) {\n                    int id = remS[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            }\n            cost += bestDist;\n            curIsSource = true;\n            curIdx = bestId;\n            load++;\n            remS[bestPos] = remS.back();\n            remS.pop_back();\n        }\n\n        while (load > 0) {\n            int bestPos = -1, bestId = -1, bestDist = INF;\n            if (curIsSource) {\n                const auto& row = ST[curIdx];\n                for (int pos = 0; pos < (int)remT.size(); pos++) {\n                    int id = remT[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            } else {\n                const auto& row = TT[curIdx];\n                for (int pos = 0; pos < (int)remT.size(); pos++) {\n                    int id = remT[pos];\n                    int d = (int)row[id];\n                    if (d < bestDist) bestDist = d, bestPos = pos, bestId = id;\n                }\n            }\n            cost += bestDist;\n            curIsSource = false;\n            curIdx = bestId;\n            load--;\n            remT[bestPos] = remT.back();\n            remT.pop_back();\n        }\n    }\n\n    return cost;\n}\n\nvector<vector<int>> generate_candidate_sets(const vector<int>& rem, const vector<Pt>& vec, const Pt& cur, int k) {\n    vector<pair<int,int>> arr;\n    arr.reserve(rem.size());\n    for (int id : rem) arr.push_back({manhattan(cur, vec[id]), id});\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    vector<vector<int>> res;\n    if (k <= 0 || k > (int)arr.size()) return res;\n\n    auto add_vec = [&](vector<int> v) {\n        sort(v.begin(), v.end());\n        if ((int)v.size() != k) return;\n        if (adjacent_find(v.begin(), v.end()) != v.end()) return;\n        res.push_back(move(v));\n    };\n\n    if (k <= 3) {\n        int P = min((int)arr.size(), (k == 3 ? 6 : 7));\n        vector<int> top(P);\n        for (int i = 0; i < P; i++) top[i] = arr[i].second;\n        if (k == 1) {\n            for (int i = 0; i < P; i++) add_vec({top[i]});\n        } else if (k == 2) {\n            for (int i = 0; i < P; i++) {\n                for (int j = i + 1; j < P; j++) add_vec({top[i], top[j]});\n            }\n        } else {\n            for (int i = 0; i < P; i++) {\n                for (int j = i + 1; j < P; j++) {\n                    for (int l = j + 1; l < P; l++) add_vec({top[i], top[j], top[l]});\n                }\n            }\n        }\n    } else {\n        vector<int> base;\n        for (int i = 0; i < k; i++) base.push_back(arr[i].second);\n        add_vec(base);\n\n        if ((int)arr.size() > k) {\n            vector<int> v = base;\n            v.back() = arr[k].second;\n            add_vec(v);\n        }\n        if ((int)arr.size() > k) {\n            vector<int> v = base;\n            v[0] = arr[k].second;\n            add_vec(v);\n        }\n        if ((int)arr.size() > k) {\n            vector<int> v = base;\n            v[k / 2] = arr[k].second;\n            add_vec(v);\n        }\n        if ((int)arr.size() > k + 1) {\n            vector<int> v = base;\n            v[0] = arr[k].second;\n            v.back() = arr[k + 1].second;\n            add_vec(v);\n        }\n        if ((int)arr.size() > k + 1 && k >= 2) {\n            vector<int> v = base;\n            v[k - 2] = arr[k].second;\n            v[k - 1] = arr[k + 1].second;\n            add_vec(v);\n        }\n    }\n\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    return res;\n}\n\nstatic inline int nearest_dist_excluding(\n    const Pt& p,\n    const vector<int>& rem,\n    const vector<Pt>& vec,\n    const vector<char>* excluded\n) {\n    int best = INF;\n    if (excluded) {\n        for (int id : rem) {\n            if ((*excluded)[id]) continue;\n            best = min(best, manhattan(p, vec[id]));\n        }\n    } else {\n        for (int id : rem) best = min(best, manhattan(p, vec[id]));\n    }\n    return best;\n}\n\nlong long tail_estimate(\n    const Pt& endPt,\n    bool pickup,\n    const vector<int>& ids,\n    const vector<int>& remS,\n    const vector<int>& remT,\n    int loadAfter,\n    int h,\n    int biasScale\n) {\n    vector<char> excluded(Qm, 0);\n    for (int id : ids) excluded[id] = 1;\n\n    int remSLeft = pickup ? (int)remS.size() - (int)ids.size() : (int)remS.size();\n    int remTLeft = pickup ? (int)remT.size() : (int)remT.size() - (int)ids.size();\n\n    int ns = INF, nt = INF;\n    if (loadAfter < h && remSLeft > 0) {\n        ns = nearest_dist_excluding(endPt, remS, src, pickup ? &excluded : nullptr);\n    }\n    if (loadAfter > 0 && remTLeft > 0) {\n        nt = nearest_dist_excluding(endPt, remT, dst, pickup ? nullptr : &excluded);\n    }\n\n    if (remSLeft == 0 && loadAfter == 0) return 0;\n    if (loadAfter == 0) return (ns >= INF ? INF64 / 4 : (long long)ns);\n    if (remSLeft == 0) return (nt >= INF ? INF64 / 4 : (long long)nt);\n    if (loadAfter == h) return (nt >= INF ? INF64 / 4 : (long long)nt);\n\n    long long a = (ns >= INF ? INF64 / 4 : (long long)ns + 1LL * biasScale * loadAfter);\n    long long b = (nt >= INF ? INF64 / 4 : (long long)nt + 1LL * biasScale * (h - loadAfter));\n    return min(a, b);\n}\n\nvoid two_opt_open_path(vector<int>& ord, bool pickup, const Pt& startPt) {\n    int k = (int)ord.size();\n    if (k <= 2) return;\n\n    auto ptOf = [&](int id) -> const Pt& {\n        return pickup ? src[id] : dst[id];\n    };\n\n    bool improved = true;\n    for (int iter = 0; iter < 4 && improved; iter++) {\n        improved = false;\n        for (int i = 0; i < k; i++) {\n            for (int j = i + 1; j < k; j++) {\n                const Pt& A = (i == 0 ? startPt : ptOf(ord[i - 1]));\n                const Pt& B = ptOf(ord[i]);\n                const Pt& C = ptOf(ord[j]);\n\n                long long delta = 0;\n                delta += manhattan(A, C) - manhattan(A, B);\n                if (j + 1 < k) {\n                    const Pt& D = ptOf(ord[j + 1]);\n                    delta += manhattan(B, D) - manhattan(C, D);\n                }\n                if (delta < 0) {\n                    reverse(ord.begin() + i, ord.begin() + j + 1);\n                    improved = true;\n                }\n            }\n        }\n    }\n}\n\nBlockSolution solve_block_fast(\n    const Pt& startPt,\n    const vector<int>& ids,\n    bool pickup,\n    const vector<int>& remS,\n    const vector<int>& remT,\n    int loadAfter,\n    int h,\n    int biasScale\n) {\n    static constexpr int EXACT_K = 10;\n\n    BlockSolution ans;\n    int k = (int)ids.size();\n    if (k == 0) {\n        ans.moveCost = 0;\n        ans.score = 0;\n        ans.endPt = startPt;\n        return ans;\n    }\n\n    vector<Pt> pts(k);\n    for (int i = 0; i < k; i++) pts[i] = pickup ? src[ids[i]] : dst[ids[i]];\n\n    if (k <= EXACT_K) {\n        int S = 1 << k;\n        vector<int> dp(S * k, INF);\n        vector<short> par(S * k, -1);\n\n        auto at = [&](int mask, int j) -> int& { return dp[mask * k + j]; };\n        auto pat = [&](int mask, int j) -> short& { return par[mask * k + j]; };\n\n        for (int j = 0; j < k; j++) at(1 << j, j) = manhattan(startPt, pts[j]);\n\n        for (int mask = 1; mask < S; mask++) {\n            for (int j = 0; j < k; j++) {\n                if (!(mask & (1 << j))) continue;\n                int cur = at(mask, j);\n                if (cur >= INF) continue;\n                int remMask = (S - 1) ^ mask;\n                for (int nj = 0; nj < k; nj++) {\n                    if (!(remMask & (1 << nj))) continue;\n                    int nmask = mask | (1 << nj);\n                    int nd = cur + manhattan(pts[j], pts[nj]);\n                    int& ref = at(nmask, nj);\n                    if (nd < ref) {\n                        ref = nd;\n                        pat(nmask, nj) = (short)j;\n                    }\n                }\n            }\n        }\n\n        int full = S - 1;\n        long long bestScore = INF64;\n        int bestEnd = -1;\n\n        for (int j = 0; j < k; j++) {\n            int base = at(full, j);\n            if (base >= INF) continue;\n            long long tail = tail_estimate(pts[j], pickup, ids, remS, remT, loadAfter, h, biasScale);\n            long long score = (long long)base + tail;\n            if (score < bestScore || (score == bestScore && (bestEnd == -1 || base < at(full, bestEnd)))) {\n                bestScore = score;\n                bestEnd = j;\n            }\n        }\n\n        if (bestEnd == -1) return ans;\n\n        vector<int> ordRev;\n        int mask = full, cur = bestEnd;\n        while (cur != -1) {\n            ordRev.push_back(ids[cur]);\n            int p = pat(mask, cur);\n            mask ^= 1 << cur;\n            cur = p;\n        }\n        reverse(ordRev.begin(), ordRev.end());\n\n        ans.moveCost = at(full, bestEnd);\n        ans.score = bestScore;\n        ans.order = move(ordRev);\n        ans.endPt = pts[bestEnd];\n        return ans;\n    }\n\n    vector<int> rem = ids;\n    vector<int> ord;\n    ord.reserve(k);\n    Pt cur = startPt;\n\n    while (!rem.empty()) {\n        int bestPos = -1, bestDist = INF;\n        for (int i = 0; i < (int)rem.size(); i++) {\n            const Pt& p = pickup ? src[rem[i]] : dst[rem[i]];\n            int d = manhattan(cur, p);\n            if (d < bestDist) {\n                bestDist = d;\n                bestPos = i;\n            }\n        }\n        int id = rem[bestPos];\n        cur = pickup ? src[id] : dst[id];\n        ord.push_back(id);\n        rem[bestPos] = rem.back();\n        rem.pop_back();\n    }\n\n    two_opt_open_path(ord, pickup, startPt);\n\n    long long mv = 0;\n    cur = startPt;\n    for (int id : ord) {\n        const Pt& p = pickup ? src[id] : dst[id];\n        mv += manhattan(cur, p);\n        cur = p;\n    }\n\n    ans.moveCost = mv;\n    ans.order = move(ord);\n    ans.endPt = cur;\n    ans.score = mv + tail_estimate(cur, pickup, ids, remS, remT, loadAfter, h, biasScale);\n    return ans;\n}\n\nvoid remove_ids_from_rem(vector<int>& rem, const vector<int>& ids) {\n    vector<char> mark(Qm, 0);\n    for (int id : ids) mark[id] = 1;\n    int w = 0;\n    for (int i = 0; i < (int)rem.size(); i++) {\n        if (!mark[rem[i]]) rem[w++] = rem[i];\n    }\n    rem.resize(w);\n}\n\nPlan make_fill_plan(int h, int startIdx, int biasScale, const Timer& timer, double limit_ms) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.cost = 2;\n    plan.name = \"fill:\" + to_string(h) + \":\" + to_string(startIdx) + \":\" + to_string(biasScale);\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    Pt cur = src[startIdx];\n    int load = 1;\n\n    while (!remS.empty() || load > 0) {\n        if (timer.over(limit_ms)) {\n            plan.cost = INF64;\n            return plan;\n        }\n\n        if (load < h && !remS.empty()) {\n            int need = min(h - load, (int)remS.size());\n            auto sets = generate_candidate_sets(remS, src, cur, need);\n\n            BlockSolution bestBS;\n            vector<int> bestIds;\n            for (auto& cand : sets) {\n                auto bs = solve_block_fast(cur, cand, true, remS, remT, load + need, h, biasScale);\n                if (bs.score < bestBS.score || (bs.score == bestBS.score && bs.moveCost < bestBS.moveCost)) {\n                    bestBS = move(bs);\n                    bestIds = cand;\n                }\n            }\n            if (bestIds.empty()) {\n                plan.cost = INF64;\n                return plan;\n            }\n\n            Block b;\n            b.pickup = true;\n            b.ids = move(bestIds);\n            b.order = move(bestBS.order);\n            b.moveCost = bestBS.moveCost;\n            b.endPt = bestBS.endPt;\n\n            plan.blocks.push_back(b);\n            plan.cost += b.moveCost;\n            remove_ids_from_rem(remS, b.ids);\n            cur = b.endPt;\n            load += need;\n        }\n\n        if (load > 0) {\n            int need = load;\n            auto sets = generate_candidate_sets(remT, dst, cur, need);\n\n            BlockSolution bestBS;\n            vector<int> bestIds;\n            for (auto& cand : sets) {\n                auto bs = solve_block_fast(cur, cand, false, remS, remT, load - need, h, biasScale);\n                if (bs.score < bestBS.score || (bs.score == bestBS.score && bs.moveCost < bestBS.moveCost)) {\n                    bestBS = move(bs);\n                    bestIds = cand;\n                }\n            }\n            if (bestIds.empty()) {\n                plan.cost = INF64;\n                return plan;\n            }\n\n            Block b;\n            b.pickup = false;\n            b.ids = move(bestIds);\n            b.order = move(bestBS.order);\n            b.moveCost = bestBS.moveCost;\n            b.endPt = bestBS.endPt;\n\n            plan.blocks.push_back(b);\n            plan.cost += b.moveCost;\n            remove_ids_from_rem(remT, b.ids);\n            cur = b.endPt;\n            load -= need;\n        }\n    }\n\n    return plan;\n}\n\nPlan make_adaptive_plan(int h, int startIdx, int biasScale, int switchPenalty, const Timer& timer, double limit_ms) {\n    Plan plan;\n    plan.startIdx = startIdx;\n    plan.h = h;\n    plan.cost = 2;\n    plan.name = \"adaptive:\" + to_string(h) + \":\" + to_string(startIdx) + \":\" + to_string(biasScale) + \":\" + to_string(switchPenalty);\n\n    vector<int> remS, remT;\n    remS.reserve(Qm - 1);\n    remT.reserve(Qm);\n    for (int i = 0; i < Qm; i++) {\n        if (i != startIdx) remS.push_back(i);\n        remT.push_back(i);\n    }\n\n    Pt cur = src[startIdx];\n    int load = 1;\n    int prevType = 1;\n\n    while (!remS.empty() || load > 0) {\n        if (timer.over(limit_ms)) {\n            plan.cost = INF64;\n            return plan;\n        }\n\n        long long bestOptionScore = INF64;\n        long long bestMoveCost = INF64;\n        Block bestBlock;\n        int bestDeltaLoad = 0;\n        int bestType = -1;\n\n        if (load < h && !remS.empty()) {\n            int maxAdd = min(h - load, (int)remS.size());\n            vector<int> sizes = {1};\n            if (maxAdd >= 2) sizes.push_back(2);\n            if (maxAdd >= 3) sizes.push_back(3);\n            if (maxAdd >= 4) sizes.push_back((maxAdd + 1) / 2);\n            if (maxAdd >= 5) sizes.push_back(maxAdd - 1);\n            if (maxAdd >= 4) sizes.push_back(maxAdd);\n            sort(sizes.begin(), sizes.end());\n            sizes.erase(unique(sizes.begin(), sizes.end()), sizes.end());\n\n            for (int k : sizes) {\n                auto sets = generate_candidate_sets(remS, src, cur, k);\n                for (auto& cand : sets) {\n                    auto bs = solve_block_fast(cur, cand, true, remS, remT, load + k, h, biasScale);\n                    long long score = bs.score + (prevType != 1 ? switchPenalty : 0);\n                    if (score < bestOptionScore || (score == bestOptionScore && bs.moveCost < bestMoveCost)) {\n                        bestOptionScore = score;\n                        bestMoveCost = bs.moveCost;\n                        bestType = 1;\n                        bestDeltaLoad = +k;\n                        bestBlock.pickup = true;\n                        bestBlock.ids = cand;\n                        bestBlock.order = move(bs.order);\n                        bestBlock.moveCost = bs.moveCost;\n                        bestBlock.endPt = bs.endPt;\n                    }\n                }\n            }\n        }\n\n        if (load > 0) {\n            int maxDrop = load;\n            vector<int> sizes = {1};\n            if (maxDrop >= 2) sizes.push_back(2);\n            if (maxDrop >= 3) sizes.push_back(3);\n            if (maxDrop >= 4) sizes.push_back((maxDrop + 1) / 2);\n            if (maxDrop >= 5) sizes.push_back(maxDrop - 1);\n            if (maxDrop >= 4) sizes.push_back(maxDrop);\n            sort(sizes.begin(), sizes.end());\n            sizes.erase(unique(sizes.begin(), sizes.end()), sizes.end());\n\n            for (int k : sizes) {\n                auto sets = generate_candidate_sets(remT, dst, cur, k);\n                for (auto& cand : sets) {\n                    auto bs = solve_block_fast(cur, cand, false, remS, remT, load - k, h, biasScale);\n                    long long score = bs.score + (prevType != 0 ? switchPenalty : 0);\n                    if (score < bestOptionScore || (score == bestOptionScore && bs.moveCost < bestMoveCost)) {\n                        bestOptionScore = score;\n                        bestMoveCost = bs.moveCost;\n                        bestType = 0;\n                        bestDeltaLoad = -k;\n                        bestBlock.pickup = false;\n                        bestBlock.ids = cand;\n                        bestBlock.order = move(bs.order);\n                        bestBlock.moveCost = bs.moveCost;\n                        bestBlock.endPt = bs.endPt;\n                    }\n                }\n            }\n        }\n\n        if (bestType == -1) {\n            plan.cost = INF64;\n            return plan;\n        }\n\n        plan.blocks.push_back(bestBlock);\n        plan.cost += bestBlock.moveCost;\n        cur = bestBlock.endPt;\n        if (bestType == 1) remove_ids_from_rem(remS, bestBlock.ids);\n        else remove_ids_from_rem(remT, bestBlock.ids);\n        load += bestDeltaLoad;\n        prevType = bestType;\n    }\n\n    return plan;\n}\n\nPlan normalize_plan(const Plan& p) {\n    Plan q;\n    q.startIdx = p.startIdx;\n    q.h = p.h;\n    q.cost = p.cost;\n    q.name = p.name + \":norm\";\n\n    for (const auto& b : p.blocks) {\n        if (b.ids.empty()) continue;\n        if (!q.blocks.empty() && q.blocks.back().pickup == b.pickup) {\n            auto& v = q.blocks.back().ids;\n            v.insert(v.end(), b.ids.begin(), b.ids.end());\n        } else {\n            Block nb;\n            nb.pickup = b.pickup;\n            nb.ids = b.ids;\n            q.blocks.push_back(move(nb));\n        }\n    }\n\n    for (auto& b : q.blocks) {\n        sort(b.ids.begin(), b.ids.end());\n        b.ids.erase(unique(b.ids.begin(), b.ids.end()), b.ids.end());\n        b.order.clear();\n        b.moveCost = 0;\n        b.endPt = {0, 0};\n    }\n    return q;\n}\n\nint path_gain_dp(const Pt& a, const Pt& b, bool pickup, const vector<char>& remainMark) {\n    static int dp[31][31];\n\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) dp[i][j] = -INF;\n    }\n    dp[0][0] = 0;\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && remainMark[idx]) add = 1;\n\n            int best = -INF;\n            if (i > 0) best = max(best, dp[i - 1][j]);\n            if (j > 0) best = max(best, dp[i][j - 1]);\n            dp[i][j] = best + add;\n        }\n    }\n    return dp[dx][dy];\n}\n\nvector<char> reconstruct_best_path(const Pt& a, const Pt& b, bool pickup, const vector<char>& remainMark) {\n    static int dp[31][31];\n    static char par[31][31];\n\n    int dx = abs(b.x - a.x);\n    int dy = abs(b.y - a.y);\n    int sx = (b.x > a.x ? 1 : (b.x < a.x ? -1 : 0));\n    int sy = (b.y > a.y ? 1 : (b.y < a.y ? -1 : 0));\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            dp[i][j] = -INF;\n            par[i][j] = '?';\n        }\n    }\n    dp[0][0] = 0;\n    par[0][0] = '.';\n\n    for (int i = 0; i <= dx; i++) {\n        for (int j = 0; j <= dy; j++) {\n            if (i == 0 && j == 0) continue;\n            int x = a.x + sx * i;\n            int y = a.y + sy * j;\n\n            int add = 0;\n            int idx = pickup ? srcIdAt[x][y] : dstIdAt[x][y];\n            if (idx != -1 && remainMark[idx]) add = 1;\n\n            int best = -INF;\n            char bp = '?';\n            if (i > 0) {\n                int cand = dp[i - 1][j] + add;\n                if (cand > best) {\n                    best = cand;\n                    bp = 'V';\n                }\n            }\n            if (j > 0) {\n                int cand = dp[i][j - 1] + add;\n                if (cand > best) {\n                    best = cand;\n                    bp = 'H';\n                }\n            }\n            dp[i][j] = best;\n            par[i][j] = bp;\n        }\n    }\n\n    vector<char> rev;\n    int i = dx, j = dy;\n    while (!(i == 0 && j == 0)) {\n        if (par[i][j] == 'V') {\n            rev.push_back(sx == 1 ? 'D' : 'U');\n            --i;\n        } else {\n            rev.push_back(sy == 1 ? 'R' : 'L');\n            --j;\n        }\n    }\n    reverse(rev.begin(), rev.end());\n    return rev;\n}\n\nExecResult execute_plan_pathaware(const Plan& plan, bool buildOps, int Vp, int leafCount) {\n    ExecResult res;\n    if (buildOps) res.ops.clear();\n\n    auto make_cmd = [&]() -> string {\n        return string(2 * Vp, '.');\n    };\n\n    Pt cur = src[plan.startIdx];\n    long long steps = 0;\n    int load = 1;\n\n    vector<int> holding(leafCount, 0);\n    if (leafCount > 0) holding[0] = 1;\n\n    auto emit_turn = [&](char mv, bool doAction, bool pickup) {\n        steps++;\n        if (!buildOps) {\n            if (doAction) {\n                if (pickup) load++;\n                else load--;\n            }\n            return;\n        }\n\n        string cmd = make_cmd();\n        cmd[0] = mv;\n\n        if (doAction) {\n            int chosen = -1;\n            if (pickup) {\n                for (int i = 0; i < leafCount; i++) {\n                    if (!holding[i]) {\n                        chosen = i;\n                        holding[i] = 1;\n                        break;\n                    }\n                }\n                if (chosen < 0) chosen = 0;\n                load++;\n            } else {\n                for (int i = 0; i < leafCount; i++) {\n                    if (holding[i]) {\n                        chosen = i;\n                        holding[i] = 0;\n                        break;\n                    }\n                }\n                if (chosen < 0) chosen = 0;\n                load--;\n            }\n            int vertex = 2 + chosen;\n            cmd[Vp + vertex] = 'P';\n        }\n\n        res.ops.push_back(move(cmd));\n    };\n\n    if (buildOps) {\n        string cmd0 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd0[u] = 'R';\n        res.ops.push_back(cmd0);\n\n        string cmd1 = make_cmd();\n        for (int u = 2; u < Vp; u++) cmd1[u] = 'R';\n        cmd1[Vp + 2] = 'P';\n        res.ops.push_back(cmd1);\n    }\n    steps += 2;\n\n    for (const auto& block : plan.blocks) {\n        vector<char> remainMark(Qm, 0);\n        int remCnt = 0;\n        for (int id : block.ids) {\n            remainMark[id] = 1;\n            remCnt++;\n        }\n\n        while (remCnt > 0) {\n            int idxCur = block.pickup ? srcIdAt[cur.x][cur.y] : dstIdAt[cur.x][cur.y];\n            if (idxCur != -1 && remainMark[idxCur]) {\n                remainMark[idxCur] = 0;\n                remCnt--;\n                emit_turn('.', true, block.pickup);\n                continue;\n            }\n\n            int minx = N, miny = N, maxx = -1, maxy = -1;\n            vector<int> remIds;\n            remIds.reserve(remCnt);\n            for (int id : block.ids) if (remainMark[id]) {\n                remIds.push_back(id);\n                const Pt& p = block.pickup ? src[id] : dst[id];\n                minx = min(minx, p.x);\n                miny = min(miny, p.y);\n                maxx = max(maxx, p.x);\n                maxy = max(maxy, p.y);\n            }\n\n            int bestGain = -1;\n            int bestDist = INF;\n            int bestIsRemain = -1;\n            Pt bestPt{-1, -1};\n\n            auto consider = [&](const Pt& p, int isRemain) {\n                if (p.x == cur.x && p.y == cur.y) return;\n                int g = path_gain_dp(cur, p, block.pickup, remainMark);\n                int d = manhattan(cur, p);\n                if (g > bestGain ||\n                    (g == bestGain && (d < bestDist ||\n                     (d == bestDist && isRemain > bestIsRemain)))) {\n                    bestGain = g;\n                    bestDist = d;\n                    bestIsRemain = isRemain;\n                    bestPt = p;\n                }\n            };\n\n            for (int id : remIds) {\n                consider(block.pickup ? src[id] : dst[id], 1);\n            }\n\n            if (remCnt >= 3) {\n                vector<Pt> extras = {\n                    {minx, miny}, {minx, maxy}, {maxx, miny}, {maxx, maxy},\n                    {(minx + maxx) / 2, (miny + maxy) / 2},\n                    {minx, (miny + maxy) / 2},\n                    {maxx, (miny + maxy) / 2},\n                    {(minx + maxx) / 2, miny},\n                    {(minx + maxx) / 2, maxy}\n                };\n                sort(extras.begin(), extras.end(), [](const Pt& a, const Pt& b) {\n                    if (a.x != b.x) return a.x < b.x;\n                    return a.y < b.y;\n                });\n                extras.erase(unique(extras.begin(), extras.end(), [](const Pt& a, const Pt& b) {\n                    return a.x == b.x && a.y == b.y;\n                }), extras.end());\n\n                for (const auto& p : extras) {\n                    consider(p, 0);\n                }\n            }\n\n            if (bestGain <= 0) {\n                int bestId = -1;\n                int d0 = INF;\n                for (int id : remIds) {\n                    Pt p = block.pickup ? src[id] : dst[id];\n                    int d = manhattan(cur, p);\n                    if (d < d0) d0 = d, bestId = id;\n                }\n                bestPt = block.pickup ? src[bestId] : dst[bestId];\n            }\n\n            vector<char> moves = reconstruct_best_path(cur, bestPt, block.pickup, remainMark);\n            if (moves.empty()) {\n                int bestId = -1;\n                int d0 = INF;\n                for (int id : remIds) {\n                    Pt p = block.pickup ? src[id] : dst[id];\n                    int d = manhattan(cur, p);\n                    if (d < d0 && !(p.x == cur.x && p.y == cur.y)) {\n                        d0 = d;\n                        bestId = id;\n                    }\n                }\n                if (bestId == -1) {\n                    int anyId = remIds[0];\n                    remainMark[anyId] = 0;\n                    remCnt--;\n                    emit_turn('.', true, block.pickup);\n                    continue;\n                }\n                bestPt = block.pickup ? src[bestId] : dst[bestId];\n                moves = reconstruct_best_path(cur, bestPt, block.pickup, remainMark);\n            }\n\n            for (char mv : moves) {\n                if (mv == 'U') cur.x--;\n                else if (mv == 'D') cur.x++;\n                else if (mv == 'L') cur.y--;\n                else if (mv == 'R') cur.y++;\n\n                bool act = false;\n                int idx = block.pickup ? srcIdAt[cur.x][cur.y] : dstIdAt[cur.x][cur.y];\n                if (idx != -1 && remainMark[idx]) {\n                    remainMark[idx] = 0;\n                    remCnt--;\n                    act = true;\n                }\n                emit_turn(mv, act, block.pickup);\n            }\n        }\n    }\n\n    if (load != 0) {\n        res.cost = INF64;\n        return res;\n    }\n    res.cost = steps;\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n    const double TIME_LIMIT_MS = 2200.0;\n\n    cin >> N >> M >> Vcap;\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    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (s[i][j] == '1' && t[i][j] == '0') src.push_back({i, j});\n            else if (s[i][j] == '0' && t[i][j] == '1') dst.push_back({i, j});\n        }\n    }\n    Qm = (int)src.size();\n\n    const int Vp = Vcap;\n    const int leafCount = Vp - 2;\n\n    auto output_tree = [&](int root_x, int root_y) {\n        cout << Vp << '\\n';\n        cout << 0 << ' ' << 1 << '\\n';\n        for (int u = 2; u < Vp; u++) cout << 1 << ' ' << 1 << '\\n';\n        cout << root_x << ' ' << root_y << '\\n';\n    };\n\n    if (Qm == 0) {\n        output_tree(0, 0);\n        return 0;\n    }\n\n    SS.assign(Qm, vector<unsigned char>(Qm));\n    ST.assign(Qm, vector<unsigned char>(Qm));\n    TS.assign(Qm, vector<unsigned char>(Qm));\n    TT.assign(Qm, vector<unsigned char>(Qm));\n    for (int i = 0; i < Qm; i++) {\n        for (int j = 0; j < Qm; j++) {\n            SS[i][j] = (unsigned char)manhattan(src[i], src[j]);\n            ST[i][j] = (unsigned char)manhattan(src[i], dst[j]);\n            TS[i][j] = (unsigned char)manhattan(dst[i], src[j]);\n            TT[i][j] = (unsigned char)manhattan(dst[i], dst[j]);\n        }\n    }\n\n    srcIdAt.assign(N, vector<int>(N, -1));\n    dstIdAt.assign(N, vector<int>(N, -1));\n    for (int i = 0; i < Qm; i++) {\n        srcIdAt[src[i].x][src[i].y] = i;\n        dstIdAt[dst[i].x][dst[i].y] = i;\n    }\n\n    vector<int> startCandidates = make_start_candidates();\n    int maxH = min(leafCount, Qm);\n\n    vector<tuple<long long,int,int>> roughList;\n    roughList.reserve((int)startCandidates.size() * maxH);\n    for (int h = 1; h <= maxH; h++) {\n        for (int st : startCandidates) {\n            roughList.emplace_back(rough_simulate(h, st), h, st);\n        }\n    }\n    sort(roughList.begin(), roughList.end());\n\n    vector<pair<int,int>> seedPairs;\n    set<pair<int,int>> usedSeed;\n\n    auto add_seed = [&](int h, int st) {\n        if (usedSeed.insert({h, st}).second) seedPairs.push_back({h, st});\n    };\n\n    for (int i = 0; i < min(6, (int)roughList.size()); i++) {\n        auto [c, h, st] = roughList[i];\n        add_seed(h, st);\n    }\n    for (int h = 1; h <= maxH && (int)seedPairs.size() < 10; h++) {\n        long long best = INF64;\n        int bst = -1;\n        for (auto &[c, hh, st] : roughList) {\n            if (hh == h && c < best) {\n                best = c;\n                bst = st;\n            }\n        }\n        if (bst != -1) add_seed(h, bst);\n    }\n    if (seedPairs.empty()) {\n        auto [c, h, st] = roughList[0];\n        seedPairs.push_back({h, st});\n    }\n\n    auto [bestH0, bestSt0] = seedPairs[0];\n    Plan bestPlan = make_fill_plan(bestH0, bestSt0, 0, timer, TIME_LIMIT_MS);\n    if (bestPlan.cost >= INF64 / 2) {\n        bestPlan = make_fill_plan(bestH0, bestSt0, 0, timer, 1e18);\n    }\n    long long bestActual = execute_plan_pathaware(bestPlan, false, Vp, leafCount).cost;\n\n    auto try_plan = [&](Plan&& p) {\n        if (p.cost >= INF64 / 2) return;\n        long long actual = execute_plan_pathaware(p, false, Vp, leafCount).cost;\n        if (actual < bestActual) {\n            bestActual = actual;\n            bestPlan = move(p);\n        }\n    };\n\n    for (int i = 0; i < (int)seedPairs.size(); i++) {\n        if (timer.over(TIME_LIMIT_MS)) break;\n        auto [h, st] = seedPairs[i];\n\n        if (i > 0) {\n            try_plan(make_fill_plan(h, st, 0, timer, TIME_LIMIT_MS));\n        }\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        try_plan(make_fill_plan(h, st, 1, timer, TIME_LIMIT_MS));\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        if (i < 4) {\n            try_plan(make_adaptive_plan(h, st, 1, 2, timer, TIME_LIMIT_MS));\n        }\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        if (i < 2) {\n            try_plan(make_adaptive_plan(h, st, 1, 1, timer, TIME_LIMIT_MS));\n        }\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        if (i < 3) {\n            try_plan(make_fill_plan(h, st, 2, timer, TIME_LIMIT_MS));\n        }\n        if (timer.over(TIME_LIMIT_MS)) break;\n\n        if (i < 2) {\n            try_plan(make_adaptive_plan(h, st, 0, 0, timer, TIME_LIMIT_MS));\n        }\n    }\n\n    {\n        Plan merged = normalize_plan(bestPlan);\n        long long actual = execute_plan_pathaware(merged, false, Vp, leafCount).cost;\n        if (actual < bestActual) {\n            bestActual = actual;\n            bestPlan = move(merged);\n        }\n    }\n\n    ExecResult bestRes = execute_plan_pathaware(bestPlan, true, Vp, leafCount);\n\n    output_tree(src[bestPlan.startIdx].x, src[bestPlan.startIdx].y);\n    for (auto& cmd : bestRes.ops) cout << cmd << '\\n';\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\n\nusing namespace std;\nusing namespace atcoder;\n\nstatic constexpr int COORD_MAX = 100000;\nstatic constexpr int ENC_SHIFT = 17;\nstatic constexpr int ENC_MASK = (1 << ENC_SHIFT) - 1;\n\nstruct Pt {\n    int x, y;\n};\n\nstruct GridData {\n    int G, sx, sy;\n    int W, H;\n    vector<int> xs, ys;\n    vector<int> w;\n};\n\nstruct Component {\n    vector<int> cells;\n    int prize = 0;\n};\n\nstruct ComponentsResult {\n    vector<Component> comps;\n    vector<int> compId;\n    int bestCid = -1;\n    int positiveCount = 0;\n};\n\nstruct Candidate {\n    vector<Pt> poly;\n    long long approx = 0;\n    int perim = 0;\n    int minx = 0, maxx = 0, miny = 0, maxy = 0;\n    uint64_t hash = 0;\n};\n\nstruct FishEnv {\n    vector<Pt> pts;\n    vector<int> sgn;\n    vector<int> ordY;\n    vector<vector<int>> byX, byY;\n};\n\nstatic inline long long enc_xy(int x, int y) {\n    return (static_cast<long long>(x) << ENC_SHIFT) | y;\n}\n\nstatic inline Pt dec_xy(long long v) {\n    return Pt{static_cast<int>(v >> ENC_SHIFT), static_cast<int>(v & ENC_MASK)};\n}\n\nstatic inline int manhattan(const Pt& a, const Pt& b) {\n    return abs(a.x - b.x) + abs(a.y - b.y);\n}\n\nvector<int> create_bounds(int G, int shift) {\n    vector<int> res;\n    res.push_back(0);\n    int cur = 0;\n    if (shift > 0) {\n        res.push_back(shift);\n        cur = shift;\n    }\n    while (cur < COORD_MAX) {\n        cur = min(COORD_MAX, cur + G);\n        if (cur > res.back()) res.push_back(cur);\n    }\n    return res;\n}\n\nint coord_to_index(int v, int G, int shift, int cells) {\n    if (v == COORD_MAX) return cells - 1;\n    if (shift > 0 && v < shift) return 0;\n    int idx;\n    if (shift == 0) idx = v / G;\n    else idx = 1 + (v - shift) / G;\n    if (idx < 0) idx = 0;\n    if (idx >= cells) idx = cells - 1;\n    return idx;\n}\n\nGridData build_grid(const vector<Pt>& macks, const vector<Pt>& sards, int G, int sx, int sy) {\n    GridData gd;\n    gd.G = G; gd.sx = sx; gd.sy = sy;\n    gd.xs = create_bounds(G, sx);\n    gd.ys = create_bounds(G, sy);\n    gd.W = (int)gd.xs.size() - 1;\n    gd.H = (int)gd.ys.size() - 1;\n    gd.w.assign(gd.W * gd.H, 0);\n\n    auto id = [&](int x, int y) { return y * gd.W + x; };\n\n    for (const auto& p : macks) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]++;\n    }\n    for (const auto& p : sards) {\n        int ix = coord_to_index(p.x, G, sx, gd.W);\n        int iy = coord_to_index(p.y, G, sy, gd.H);\n        gd.w[id(ix, iy)]--;\n    }\n    return gd;\n}\n\nlong long region_sum(const vector<char>& occ, const vector<int>& w) {\n    long long s = 0;\n    for (int i = 0; i < (int)occ.size(); i++) if (occ[i]) s += w[i];\n    return s;\n}\n\nvector<char> best_rectangle_region(const GridData& gd) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    long long best = LLONG_MIN;\n    int bestL = -1, bestR = -1, bestB = -1, bestT = -1;\n\n    vector<long long> tmp(H);\n    for (int L = 0; L < W; L++) {\n        fill(tmp.begin(), tmp.end(), 0);\n        for (int R = L; R < W; R++) {\n            for (int y = 0; y < H; y++) tmp[y] += gd.w[id(R, y)];\n            long long cur = 0;\n            int st = 0;\n            for (int y = 0; y < H; y++) {\n                if (cur <= 0) {\n                    cur = tmp[y];\n                    st = y;\n                } else {\n                    cur += tmp[y];\n                }\n                if (cur > best) {\n                    best = cur;\n                    bestL = L; bestR = R; bestB = st; bestT = y;\n                }\n            }\n        }\n    }\n\n    vector<char> occ(W * H, 0);\n    if (best <= 0 || bestL < 0) return occ;\n    for (int y = bestB; y <= bestT; y++) {\n        for (int x = bestL; x <= bestR; x++) occ[id(x, y)] = 1;\n    }\n    return occ;\n}\n\nvector<char> graph_cut_select(const GridData& gd, int lambda) {\n    int W = gd.W, H = gd.H;\n    int V = W * H;\n    int S = V, T = V + 1;\n    mf_graph<long long> mf(V + 2);\n\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            int ww = gd.w[v];\n            if (ww >= 0) mf.add_edge(S, v, ww);\n            else mf.add_edge(v, T, -ww);\n\n            int border = 0;\n            if (x == 0) border++;\n            if (x == W - 1) border++;\n            if (y == 0) border++;\n            if (y == H - 1) border++;\n            if (border) mf.add_edge(v, T, 1LL * lambda * border);\n\n            if (x + 1 < W) {\n                int u = id(x + 1, y);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n            if (y + 1 < H) {\n                int u = id(x, y + 1);\n                mf.add_edge(v, u, lambda);\n                mf.add_edge(u, v, lambda);\n            }\n        }\n    }\n\n    mf.flow(S, T);\n    auto cut = mf.min_cut(S);\n    vector<char> sel(V, 0);\n    for (int i = 0; i < V; i++) sel[i] = cut[i] ? 1 : 0;\n    return sel;\n}\n\nComponentsResult get_components(const vector<char>& sel, const vector<int>& w, int W, int H) {\n    ComponentsResult res;\n    int V = W * H;\n    res.compId.assign(V, -1);\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    int cid = 0;\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int s = id(x, y);\n            if (!sel[s] || res.compId[s] != -1) continue;\n\n            queue<int> q;\n            q.push(s);\n            res.compId[s] = cid;\n            Component comp;\n\n            while (!q.empty()) {\n                int v = q.front(); q.pop();\n                comp.cells.push_back(v);\n                comp.prize += w[v];\n\n                int vx = v % W, vy = v / W;\n                static const int dx[4] = {1, -1, 0, 0};\n                static const int dy[4] = {0, 0, 1, -1};\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = vx + dx[dir], ny = vy + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (!sel[u] || res.compId[u] != -1) continue;\n                    res.compId[u] = cid;\n                    q.push(u);\n                }\n            }\n\n            res.comps.push_back(std::move(comp));\n            cid++;\n        }\n    }\n\n    int bestPrize = INT_MIN;\n    for (int i = 0; i < (int)res.comps.size(); i++) {\n        if (res.comps[i].prize > 0) {\n            res.positiveCount++;\n            if (res.comps[i].prize > bestPrize) {\n                bestPrize = res.comps[i].prize;\n                res.bestCid = i;\n            }\n        }\n    }\n    return res;\n}\n\nvoid fill_holes(vector<char>& occ, int W, int H) {\n    int PW = W + 2, PH = H + 2;\n    vector<char> vis(PW * PH, 0);\n\n    auto pid = [&](int x, int y) { return y * PW + x; };\n    auto blocked = [&](int x, int y) -> bool {\n        if (x == 0 || x == W + 1 || y == 0 || y == H + 1) return false;\n        return occ[(y - 1) * W + (x - 1)];\n    };\n\n    queue<int> q;\n    q.push(pid(0, 0));\n    vis[pid(0, 0)] = 1;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % PW, y = v / PW;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (nx < 0 || nx >= PW || ny < 0 || ny >= PH) continue;\n            int u = pid(nx, ny);\n            if (vis[u] || blocked(nx, ny)) continue;\n            vis[u] = 1;\n            q.push(u);\n        }\n    }\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = y * W + x;\n            if (!occ[v] && !vis[pid(x + 1, y + 1)]) occ[v] = 1;\n        }\n    }\n}\n\nint count_occ_neighbors(const vector<char>& occ, int v, int W, int H) {\n    int x = v % W, y = v / W;\n    int k = 0;\n    if (x > 0 && occ[v - 1]) k++;\n    if (x + 1 < W && occ[v + 1]) k++;\n    if (y > 0 && occ[v - W]) k++;\n    if (y + 1 < H && occ[v + W]) k++;\n    return k;\n}\n\nbool is_boundary_cell(const vector<char>& occ, int v, int W, int H) {\n    if (!occ[v]) return false;\n    int x = v % W, y = v / W;\n    if (x == 0 || x == W - 1 || y == 0 || y == H - 1) return true;\n    if (!occ[v - 1] || !occ[v + 1] || !occ[v - W] || !occ[v + W]) return true;\n    return false;\n}\n\nbool can_remove_connected(const vector<char>& occ, int rem, int W, int H, int occCount) {\n    if (occCount <= 1) return false;\n    int k = count_occ_neighbors(occ, rem, W, H);\n    if (k <= 1) return true;\n\n    int start = -1;\n    for (int i = 0; i < (int)occ.size(); i++) {\n        if (i != rem && occ[i]) {\n            start = i;\n            break;\n        }\n    }\n    if (start == -1) return false;\n\n    vector<char> vis(occ.size(), 0);\n    queue<int> q;\n    q.push(start);\n    vis[start] = 1;\n    int seen = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    while (!q.empty()) {\n        int v = q.front(); q.pop();\n        int x = v % W, y = v / W;\n        for (int dir = 0; dir < 4; dir++) {\n            int nx = x + dx[dir], ny = y + dy[dir];\n            if (!inside(nx, ny)) continue;\n            int u = id(nx, ny);\n            if (u == rem || !occ[u] || vis[u]) continue;\n            vis[u] = 1;\n            seen++;\n            q.push(u);\n        }\n    }\n    return seen == occCount - 1;\n}\n\nvoid local_hill_climb(vector<char>& occ, const vector<int>& w, int W, int H, int beta) {\n    auto id = [&](int x, int y) { return y * W + x; };\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n\n    int occCount = 0;\n    for (char c : occ) if (c) occCount++;\n\n    static const int dx[4] = {1, -1, 0, 0};\n    static const int dy[4] = {0, 0, 1, -1};\n\n    for (int pass = 0; pass < 3; pass++) {\n        bool changed = false;\n\n        {\n            vector<pair<int,int>> cand;\n            for (int v = 0; v < W * H; v++) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                bool adj = false;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) {\n                        adj = true;\n                        k++;\n                    }\n                }\n                if (!adj) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 60) cand.resize(60);\n\n            for (auto [ng, v] : cand) {\n                if (occ[v]) continue;\n                int x = v % W, y = v / W;\n                int k = 0;\n                for (int dir = 0; dir < 4; dir++) {\n                    int nx = x + dx[dir], ny = y + dy[dir];\n                    if (!inside(nx, ny)) continue;\n                    int u = id(nx, ny);\n                    if (occ[u]) k++;\n                }\n                if (k == 0) continue;\n                int gain = w[v] - beta * (4 - 2 * k);\n                if (gain > 0) {\n                    occ[v] = 1;\n                    occCount++;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        {\n            vector<pair<int,int>> cand;\n            for (int v = 0; v < W * H; v++) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain > 0) cand.push_back({-gain, v});\n            }\n            sort(cand.begin(), cand.end());\n            if ((int)cand.size() > 60) cand.resize(60);\n\n            for (auto [ng, v] : cand) {\n                if (!occ[v] || !is_boundary_cell(occ, v, W, H)) continue;\n                int k = count_occ_neighbors(occ, v, W, H);\n                int gain = -w[v] + beta * (4 - 2 * k);\n                if (gain <= 0) continue;\n                if (can_remove_connected(occ, v, W, H, occCount)) {\n                    occ[v] = 0;\n                    occCount--;\n                    changed = true;\n                }\n            }\n            if (changed) fill_holes(occ, W, H);\n        }\n\n        if (!changed) break;\n    }\n}\n\nvoid refine_occ(vector<char>& occ, const vector<int>& w, int W, int H) {\n    fill_holes(occ, W, H);\n    local_hill_climb(occ, w, W, H, 1);\n    local_hill_climb(occ, w, W, H, 2);\n    fill_holes(occ, W, H);\n}\n\nvector<int> top_positive_components(const ComponentsResult& cr, int K) {\n    vector<int> ids;\n    for (int i = 0; i < (int)cr.comps.size(); i++) {\n        if (cr.comps[i].prize > 0) ids.push_back(i);\n    }\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (cr.comps[a].prize != cr.comps[b].prize) return cr.comps[a].prize > cr.comps[b].prize;\n        return cr.comps[a].cells.size() < cr.comps[b].cells.size();\n    });\n    if ((int)ids.size() > K) ids.resize(K);\n    return ids;\n}\n\nvector<char> greedy_connect_mode(\n    const vector<char>& sel,\n    const ComponentsResult& cr,\n    const vector<int>& w,\n    int W, int H,\n    int seedCid,\n    int mode\n) {\n    int V = W * H;\n    vector<char> occ(V, 0);\n    if (seedCid < 0 || seedCid >= (int)cr.comps.size()) return occ;\n    if (cr.comps[seedCid].prize <= 0) return occ;\n\n    int C = (int)cr.comps.size();\n    vector<char> goodComp(C, 0);\n    for (int i = 0; i < C; i++) goodComp[i] = (cr.comps[i].prize > 0);\n\n    vector<char> added(C, 0);\n    for (int v : cr.comps[seedCid].cells) occ[v] = 1;\n    added[seedCid] = 1;\n\n    auto inside = [&](int x, int y) { return 0 <= x && x < W && 0 <= y && y < H; };\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    auto is_good_sel = [&](int v) -> bool {\n        if (!sel[v]) return false;\n        int cid = cr.compId[v];\n        return cid >= 0 && goodComp[cid];\n    };\n\n    int gainMul = (mode == 0 ? 8 : 12);\n\n    auto enter_cost = [&](int v) -> int {\n        if (occ[v]) return 0;\n        if (is_good_sel(v)) return 0;\n        int ww = w[v];\n        if (mode == 0) {\n            if (ww >= 2) return 0;\n            if (ww == 1) return 1;\n            if (ww == 0) return 4;\n            return 4 + 6 * (-ww);\n        } else {\n            if (ww >= 1) return 0;\n            if (ww == 0) return 2;\n            return 2 + 4 * (-ww);\n        }\n    };\n\n    for (int iter = 0; iter < 12; iter++) {\n        const int INF = 1e9;\n        vector<int> dist(V, INF), parent(V, -1);\n        priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;\n\n        for (int v = 0; v < V; v++) {\n            if (occ[v]) {\n                dist[v] = 0;\n                pq.push({0, v});\n            }\n        }\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n            int x = v % W, y = v / W;\n            static const int dx[4] = {1, -1, 0, 0};\n            static const int dy[4] = {0, 0, 1, -1};\n            for (int dir = 0; dir < 4; dir++) {\n                int nx = x + dx[dir], ny = y + dy[dir];\n                if (!inside(nx, ny)) continue;\n                int u = id(nx, ny);\n                int nd = d + enter_cost(u);\n                if (nd < dist[u]) {\n                    dist[u] = nd;\n                    parent[u] = v;\n                    pq.push({nd, u});\n                }\n            }\n        }\n\n        long long bestGain = 0;\n        int chooseCid = -1;\n        int chooseCell = -1;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!goodComp[cid] || added[cid]) continue;\n            int bestDist = INF;\n            int bestCell = -1;\n            for (int v : cr.comps[cid].cells) {\n                if (dist[v] < bestDist) {\n                    bestDist = dist[v];\n                    bestCell = v;\n                }\n            }\n            if (bestCell == -1) continue;\n            long long gain = 1LL * gainMul * cr.comps[cid].prize - bestDist;\n            if (gain > bestGain) {\n                bestGain = gain;\n                chooseCid = cid;\n                chooseCell = bestCell;\n            }\n        }\n\n        if (chooseCid == -1) break;\n\n        vector<char> touched(C, 0);\n        int v = chooseCell;\n        while (v != -1 && !occ[v]) {\n            occ[v] = 1;\n            if (is_good_sel(v)) touched[cr.compId[v]] = 1;\n            v = parent[v];\n        }\n        touched[chooseCid] = 1;\n\n        bool anyNew = false;\n        for (int cid = 0; cid < C; cid++) {\n            if (!touched[cid] || added[cid]) continue;\n            added[cid] = 1;\n            anyNew = true;\n            for (int u : cr.comps[cid].cells) occ[u] = 1;\n        }\n        if (!anyNew) break;\n    }\n\n    return occ;\n}\n\nvector<char> bbox_occ_from_cells(const vector<int>& cells, int W, int H) {\n    vector<char> occ(W * H, 0);\n    if (cells.empty()) return occ;\n    int minx = W, maxx = -1, miny = H, maxy = -1;\n    for (int v : cells) {\n        int x = v % W, y = v / W;\n        minx = min(minx, x);\n        maxx = max(maxx, x);\n        miny = min(miny, y);\n        maxy = max(maxy, y);\n    }\n    for (int y = miny; y <= maxy; y++) {\n        for (int x = minx; x <= maxx; x++) occ[y * W + x] = 1;\n    }\n    return occ;\n}\n\nvector<Pt> build_polygon(const GridData& gd, const vector<char>& occ) {\n    int W = gd.W, H = gd.H;\n    auto id = [&](int x, int y) { return y * W + x; };\n\n    unordered_map<long long, long long> nxt;\n    nxt.reserve((size_t)occ.size() * 3 + 16);\n    bool bad = false;\n    long long start = -1;\n\n    auto add_edge = [&](int x1, int y1, int x2, int y2) {\n        long long a = enc_xy(x1, y1);\n        long long b = enc_xy(x2, y2);\n        auto it = nxt.find(a);\n        if (it != nxt.end() && it->second != b) bad = true;\n        nxt[a] = b;\n        if (start == -1 || a < start) start = a;\n    };\n\n    for (int y = 0; y < H; y++) {\n        for (int x = 0; x < W; x++) {\n            int v = id(x, y);\n            if (!occ[v]) continue;\n            int x0 = gd.xs[x], x1 = gd.xs[x + 1];\n            int y0 = gd.ys[y], y1 = gd.ys[y + 1];\n\n            if (y == 0 || !occ[id(x, y - 1)]) add_edge(x0, y0, x1, y0);\n            if (x == W - 1 || !occ[id(x + 1, y)]) add_edge(x1, y0, x1, y1);\n            if (y == H - 1 || !occ[id(x, y + 1)]) add_edge(x1, y1, x0, y1);\n            if (x == 0 || !occ[id(x - 1, y)]) add_edge(x0, y1, x0, y0);\n        }\n    }\n\n    if (bad || start == -1) return {};\n\n    vector<Pt> poly;\n    long long cur = start;\n    int steps = 0;\n\n    while (true) {\n        poly.push_back(dec_xy(cur));\n        auto it = nxt.find(cur);\n        if (it == nxt.end()) return {};\n        cur = it->second;\n        steps++;\n        if (cur == start) break;\n        if (steps > (int)nxt.size() + 5) return {};\n    }\n\n    if (steps != (int)nxt.size()) return {};\n\n    auto collinear = [&](const Pt& a, const Pt& b, const Pt& c) {\n        return (a.x == b.x && b.x == c.x) || (a.y == b.y && b.y == c.y);\n    };\n\n    bool changed = true;\n    while (changed && (int)poly.size() > 4) {\n        changed = false;\n        vector<Pt> np;\n        int m = (int)poly.size();\n        np.reserve(m);\n        for (int i = 0; i < m; i++) {\n            const Pt& prev = poly[(i - 1 + m) % m];\n            const Pt& curp = poly[i];\n            const Pt& nextp = poly[(i + 1) % m];\n            if (collinear(prev, curp, nextp)) changed = true;\n            else np.push_back(curp);\n        }\n        poly.swap(np);\n    }\n\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return {};\n\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        long long e = enc_xy(poly[i].x, poly[i].y);\n        if (!seen.insert(e).second) return {};\n        perim += manhattan(poly[i], poly[(i + 1) % poly.size()]);\n    }\n    if (perim > 400000) return {};\n\n    return poly;\n}\n\nbool basic_valid_poly(const vector<Pt>& poly) {\n    if ((int)poly.size() < 4 || (int)poly.size() > 1000) return false;\n    unordered_set<long long> seen;\n    seen.reserve(poly.size() * 2 + 1);\n    int perim = 0;\n    for (int i = 0; i < (int)poly.size(); i++) {\n        const auto& a = poly[i];\n        const auto& b = poly[(i + 1) % poly.size()];\n        if (a.x != b.x && a.y != b.y) return false;\n        if (a.x == b.x && a.y == b.y) return false;\n        if (a.x < 0 || a.x > COORD_MAX || a.y < 0 || a.y > COORD_MAX) return false;\n        long long e = enc_xy(a.x, a.y);\n        if (!seen.insert(e).second) return false;\n        perim += manhattan(a, b);\n    }\n    return perim <= 400000;\n}\n\nuint64_t hash_poly(const vector<Pt>& poly) {\n    uint64_t h = 1469598103934665603ULL;\n    for (const auto& p : poly) {\n        uint64_t v = (uint64_t)p.x * 1000003ULL + (uint64_t)p.y + 0x9e3779b97f4a7c15ULL;\n        h ^= v;\n        h *= 1099511628211ULL;\n    }\n    h ^= (uint64_t)poly.size() + 0x517cc1b727220a95ULL;\n    return h;\n}\n\nCandidate make_candidate(vector<Pt> poly, long long approx) {\n    Candidate c;\n    c.poly = std::move(poly);\n    c.approx = approx;\n    c.perim = 0;\n    c.minx = c.maxx = c.poly[0].x;\n    c.miny = c.maxy = c.poly[0].y;\n    for (int i = 0; i < (int)c.poly.size(); i++) {\n        c.perim += manhattan(c.poly[i], c.poly[(i + 1) % c.poly.size()]);\n        c.minx = min(c.minx, c.poly[i].x);\n        c.maxx = max(c.maxx, c.poly[i].x);\n        c.miny = min(c.miny, c.poly[i].y);\n        c.maxy = max(c.maxy, c.poly[i].y);\n    }\n    c.hash = hash_poly(c.poly);\n    return c;\n}\n\npair<vector<int>, bool> snap_axis_values(const vector<int>& vals, const vector<char>& has) {\n    vector<int> nv = vals;\n    bool changed = false;\n    int K = (int)vals.size();\n    for (int i = 0; i < K; i++) {\n        int L = (i == 0 ? 0 : nv[i - 1] + 1);\n        int R = (i + 1 < K ? vals[i + 1] - 1 : COORD_MAX);\n        if (L > R) {\n            nv[i] = vals[i];\n            continue;\n        }\n        if (!has[vals[i]]) {\n            nv[i] = vals[i];\n            continue;\n        }\n        int best = vals[i];\n        bool found = false;\n        int lim = max(vals[i] - L, R - vals[i]);\n        for (int d = 1; d <= lim; d++) {\n            int a = vals[i] - d;\n            if (a >= L && !has[a]) {\n                best = a;\n                found = true;\n                break;\n            }\n            int b = vals[i] + d;\n            if (b <= R && !has[b]) {\n                best = b;\n                found = true;\n                break;\n            }\n        }\n        if (found) {\n            nv[i] = best;\n            if (best != vals[i]) changed = true;\n        } else {\n            nv[i] = vals[i];\n        }\n    }\n    return {nv, changed};\n}\n\nvector<Pt> snap_poly_lines_mode(\n    const vector<Pt>& poly,\n    const vector<char>& hasX,\n    const vector<char>& hasY,\n    bool useX,\n    bool useY\n) {\n    if (!useX && !useY) return {};\n\n    vector<int> ux, uy;\n    ux.reserve(poly.size());\n    uy.reserve(poly.size());\n    for (auto& p : poly) {\n        ux.push_back(p.x);\n        uy.push_back(p.y);\n    }\n    sort(ux.begin(), ux.end());\n    ux.erase(unique(ux.begin(), ux.end()), ux.end());\n    sort(uy.begin(), uy.end());\n    uy.erase(unique(uy.begin(), uy.end()), uy.end());\n\n    vector<int> nx = ux, ny = uy;\n    bool cx = false, cy = false;\n    if (useX) {\n        auto r = snap_axis_values(ux, hasX);\n        nx = std::move(r.first);\n        cx = r.second;\n    }\n    if (useY) {\n        auto r = snap_axis_values(uy, hasY);\n        ny = std::move(r.first);\n        cy = r.second;\n    }\n    if (!cx && !cy) return {};\n\n    unordered_map<int,int> mx, my;\n    mx.reserve(ux.size() * 2 + 1);\n    my.reserve(uy.size() * 2 + 1);\n    for (int i = 0; i < (int)ux.size(); i++) mx[ux[i]] = nx[i];\n    for (int i = 0; i < (int)uy.size(); i++) my[uy[i]] = ny[i];\n\n    vector<Pt> out = poly;\n    for (auto& p : out) {\n        if (useX) p.x = mx[p.x];\n        if (useY) p.y = my[p.y];\n    }\n    if (!basic_valid_poly(out)) return {};\n    return out;\n}\n\nbool push_candidate(\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    vector<Pt> poly,\n    long long approx\n) {\n    if (poly.empty()) return false;\n    Candidate c = make_candidate(std::move(poly), approx);\n    if (!seenHash.insert(c.hash).second) return false;\n    cands.push_back(std::move(c));\n    return true;\n}\n\nvoid try_add_candidate(\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const GridData& gd,\n    const vector<char>& occ,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    long long approx = region_sum(occ, gd.w);\n    if (approx < 0) return;\n\n    auto poly = build_polygon(gd, occ);\n    if (poly.empty()) return;\n\n    push_candidate(cands, seenHash, poly, approx);\n\n    auto snapXY = snap_poly_lines_mode(poly, hasX, hasY, true, true);\n    if (!snapXY.empty()) push_candidate(cands, seenHash, std::move(snapXY), approx);\n\n    if ((int)poly.size() <= 120) {\n        auto snapX = snap_poly_lines_mode(poly, hasX, hasY, true, false);\n        if (!snapX.empty()) push_candidate(cands, seenHash, std::move(snapX), approx);\n        auto snapY = snap_poly_lines_mode(poly, hasX, hasY, false, true);\n        if (!snapY.empty()) push_candidate(cands, seenHash, std::move(snapY), approx);\n    }\n}\n\nstruct LazyFenwick {\n    int n = 0;\n    vector<int> bit;\n    vector<int> seen;\n    int stamp = 1;\n\n    void init(int n_) {\n        n = n_;\n        bit.assign(n + 1, 0);\n        seen.assign(n + 1, 0);\n        stamp = 1;\n    }\n\n    void next() {\n        stamp++;\n        if (stamp == INT_MAX) {\n            fill(seen.begin(), seen.end(), 0);\n            stamp = 1;\n        }\n    }\n\n    inline void add_coord(int coord, int val) {\n        for (int i = coord + 1; i <= n; i += i & -i) {\n            if (seen[i] != stamp) {\n                seen[i] = stamp;\n                bit[i] = 0;\n            }\n            bit[i] += val;\n        }\n    }\n\n    inline int sum_exclusive(int x) const {\n        int s = 0;\n        for (int i = x; i > 0; i -= i & -i) {\n            if (seen[i] == stamp) s += bit[i];\n        }\n        return s;\n    }\n};\n\nstruct ExactScorer {\n    const FishEnv& env;\n    LazyFenwick fw;\n    vector<int> onStamp;\n    int curStamp = 1;\n    vector<pair<int,int>> addEv, remEv;\n\n    ExactScorer(const FishEnv& env_) : env(env_) {\n        fw.init(COORD_MAX + 1);\n        onStamp.assign(env.pts.size(), 0);\n    }\n\n    inline void next_stamp() {\n        curStamp++;\n        if (curStamp == INT_MAX) {\n            fill(onStamp.begin(), onStamp.end(), 0);\n            curStamp = 1;\n        }\n        fw.next();\n        addEv.clear();\n        remEv.clear();\n    }\n\n    int raw_score(const Candidate& c) {\n        next_stamp();\n        addEv.reserve(c.poly.size());\n        remEv.reserve(c.poly.size());\n\n        int m = (int)c.poly.size();\n        for (int i = 0; i < m; i++) {\n            Pt a = c.poly[i];\n            Pt b = c.poly[(i + 1) % m];\n            if (a.x == b.x) {\n                int x = a.x;\n                int y1 = min(a.y, b.y), y2 = max(a.y, b.y);\n\n                for (int idx : env.byX[x]) {\n                    int py = env.pts[idx].y;\n                    if (y1 <= py && py <= y2) onStamp[idx] = curStamp;\n                }\n                if (y1 < y2) {\n                    addEv.push_back({y1, x});\n                    remEv.push_back({y2, x});\n                }\n            } else {\n                int y = a.y;\n                int x1 = min(a.x, b.x), x2 = max(a.x, b.x);\n\n                for (int idx : env.byY[y]) {\n                    int px = env.pts[idx].x;\n                    if (x1 <= px && px <= x2) onStamp[idx] = curStamp;\n                }\n            }\n        }\n\n        sort(addEv.begin(), addEv.end());\n        sort(remEv.begin(), remEv.end());\n\n        int ai = 0, ri = 0;\n        int diff = 0;\n\n        for (int idx : env.ordY) {\n            const Pt& p = env.pts[idx];\n            if (p.y < c.miny) continue;\n            if (p.y > c.maxy) break;\n\n            while (ri < (int)remEv.size() && remEv[ri].first <= p.y) {\n                fw.add_coord(remEv[ri].second, -1);\n                ri++;\n            }\n            while (ai < (int)addEv.size() && addEv[ai].first <= p.y) {\n                fw.add_coord(addEv[ai].second, +1);\n                ai++;\n            }\n\n            if (p.x < c.minx || p.x > c.maxx) continue;\n            bool inside = (onStamp[idx] == curStamp) ? true : ((fw.sum_exclusive(p.x) & 1) != 0);\n            if (inside) diff += env.sgn[idx];\n        }\n\n        return max(0, diff + 1);\n    }\n};\n\nstruct CachedExactScorer {\n    ExactScorer scorer;\n    unordered_map<uint64_t, int> cache;\n    CachedExactScorer(const FishEnv& env) : scorer(env) {\n        cache.reserve(20000);\n    }\n    int score(const Candidate& c) {\n        auto it = cache.find(c.hash);\n        if (it != cache.end()) return it->second;\n        int s = scorer.raw_score(c);\n        cache.emplace(c.hash, s);\n        return s;\n    }\n};\n\nvoid build_free_arrays(const vector<char>& has, vector<int>& prevFree, vector<int>& nextFree) {\n    prevFree.assign(COORD_MAX + 1, -1);\n    nextFree.assign(COORD_MAX + 1, COORD_MAX + 1);\n    int last = -1;\n    for (int i = 0; i <= COORD_MAX; i++) {\n        if (!has[i]) last = i;\n        prevFree[i] = last;\n    }\n    int nxt = COORD_MAX + 1;\n    for (int i = COORD_MAX; i >= 0; i--) {\n        if (!has[i]) nxt = i;\n        nextFree[i] = nxt;\n    }\n}\n\nvector<Pt> find_empty_square(const unordered_set<long long>& pts) {\n    auto has = [&](int x, int y) -> bool {\n        return pts.find(1LL * x * (COORD_MAX + 1) + y) != pts.end();\n    };\n    for (int x = 0; x <= 1000; x++) {\n        for (int y = 0; y <= 1000; y++) {\n            if (x + 1 > COORD_MAX || y + 1 > COORD_MAX) continue;\n            if (!has(x, y) && !has(x + 1, y) && !has(x, y + 1) && !has(x + 1, y + 1)) {\n                return {{x, y}, {x + 1, y}, {x + 1, y + 1}, {x, y + 1}};\n            }\n        }\n    }\n    return {{0, 0}, {1, 0}, {1, 1}, {0, 1}};\n}\n\nvoid process_selection(\n    const GridData& gd,\n    const vector<char>& sel,\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    auto cr = get_components(sel, gd.w, gd.W, gd.H);\n    auto top = top_positive_components(cr, 3);\n    if (top.empty()) return;\n\n    for (int cid : top) {\n        vector<char> occ(gd.W * gd.H, 0);\n        for (int v : cr.comps[cid].cells) occ[v] = 1;\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n\n    int seeds = min(2, (int)top.size());\n    for (int i = 0; i < seeds; i++) {\n        int cid = top[i];\n        auto occ = greedy_connect_mode(sel, cr, gd.w, gd.W, gd.H, cid, 0);\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n\n    {\n        int cid = top[0];\n        auto occ = greedy_connect_mode(sel, cr, gd.w, gd.W, gd.H, cid, 1);\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n    }\n}\n\nvoid process_selection_light(\n    const GridData& gd,\n    const vector<char>& sel,\n    vector<Candidate>& cands,\n    unordered_set<uint64_t>& seenHash,\n    const vector<char>& hasX,\n    const vector<char>& hasY\n) {\n    auto cr = get_components(sel, gd.w, gd.W, gd.H);\n    auto top = top_positive_components(cr, 2);\n    if (top.empty()) return;\n\n    for (int ti = 0; ti < (int)top.size(); ti++) {\n        int cid = top[ti];\n        vector<char> occ(gd.W * gd.H, 0);\n        for (int v : cr.comps[cid].cells) occ[v] = 1;\n        fill_holes(occ, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n\n        auto occ2 = occ;\n        refine_occ(occ2, gd.w, gd.W, gd.H);\n        try_add_candidate(cands, seenHash, gd, occ2, hasX, hasY);\n\n        if (ti == 0) {\n            auto box = bbox_occ_from_cells(cr.comps[cid].cells, gd.W, gd.H);\n            fill_holes(box, gd.W, gd.H);\n            try_add_candidate(cands, seenHash, gd, box, hasX, hasY);\n        }\n    }\n}\n\n// ----- exact local optimization -----\n\nvoid extract_axis_levels(const Candidate& c, bool useX, vector<int>& levels, vector<int>& freq) {\n    levels.clear();\n    levels.reserve(c.poly.size());\n    for (const auto& p : c.poly) levels.push_back(useX ? p.x : p.y);\n    sort(levels.begin(), levels.end());\n    levels.erase(unique(levels.begin(), levels.end()), levels.end());\n\n    freq.assign(levels.size(), 0);\n    for (const auto& p : c.poly) {\n        int v = useX ? p.x : p.y;\n        int idx = (int)(lower_bound(levels.begin(), levels.end(), v) - levels.begin());\n        freq[idx]++;\n    }\n}\n\nvector<int> pick_level_indices(const vector<int>& levels, const vector<int>& freq, int K) {\n    int n = (int)levels.size();\n    vector<int> res;\n    if (n == 0) return res;\n\n    vector<char> used(n, 0);\n    auto take = [&](int i) {\n        if (0 <= i && i < n && !used[i]) {\n            used[i] = 1;\n            res.push_back(i);\n        }\n    };\n\n    take(0);\n    take(n - 1);\n\n    vector<pair<int,int>> ord;\n    ord.reserve(n);\n    for (int i = 0; i < n; i++) ord.push_back({-freq[i], i});\n    sort(ord.begin(), ord.end());\n\n    for (auto [nf, i] : ord) {\n        take(i);\n        if ((int)res.size() >= K) break;\n    }\n    return res;\n}\n\nstatic inline void add_free_near(\n    vector<int>& res, int pos, int L, int R,\n    const vector<int>& prevFree, const vector<int>& nextFree\n) {\n    pos = max(0, min(COORD_MAX, pos));\n    pos = max(L, min(R, pos));\n    int a = prevFree[pos];\n    int b = nextFree[pos];\n    if (a >= L) res.push_back(a);\n    if (b <= R) res.push_back(b);\n}\n\nvector<int> axis_candidate_values(\n    const vector<int>& fishVals, int cur, int L, int R,\n    const vector<int>& prevFree, const vector<int>& nextFree\n) {\n    vector<int> res;\n    auto add = [&](int v) {\n        if (v < L || v > R) return;\n        res.push_back(v);\n    };\n    auto add_fish = [&](int fv) {\n        if (fv < L || fv > R) return;\n        add(fv);\n        add(fv - 1);\n        add(fv + 1);\n        add_free_near(res, fv, L, R, prevFree, nextFree);\n    };\n\n    add(cur);\n    add(cur - 1);\n    add(cur + 1);\n    add(cur - 2);\n    add(cur + 2);\n    add(cur - 3);\n    add(cur + 3);\n    add(L);\n    add(R);\n    add((L + R) / 2);\n\n    add_free_near(res, cur, L, R, prevFree, nextFree);\n    add_free_near(res, L, L, R, prevFree, nextFree);\n    add_free_near(res, R, L, R, prevFree, nextFree);\n\n    auto proc_index = [&](int idx) {\n        if (0 <= idx && idx < (int)fishVals.size()) add_fish(fishVals[idx]);\n    };\n\n    int pos = (int)(lower_bound(fishVals.begin(), fishVals.end(), cur) - fishVals.begin());\n    for (int d = -4; d <= 4; d++) proc_index(pos + d);\n\n    int posL = (int)(lower_bound(fishVals.begin(), fishVals.end(), L) - fishVals.begin());\n    for (int d = -1; d <= 2; d++) proc_index(posL + d);\n\n    int posR = (int)(upper_bound(fishVals.begin(), fishVals.end(), R) - fishVals.begin()) - 1;\n    for (int d = -2; d <= 1; d++) proc_index(posR + d);\n\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    return res;\n}\n\nvector<int> shift_candidate_values(\n    const vector<int>& fishVals, int mn, int mx, int lo, int hi,\n    const vector<int>& prevFree, const vector<int>& nextFree\n) {\n    vector<int> res;\n    auto addd = [&](int d) {\n        if (d < lo || d > hi) return;\n        res.push_back(d);\n    };\n    auto add_from_target = [&](int t, int base) {\n        addd(t - base);\n        addd(t - 1 - base);\n        addd(t + 1 - base);\n    };\n    auto add_free_for_boundary = [&](int pos, int base) {\n        pos = max(0, min(COORD_MAX, pos));\n        int a = prevFree[pos];\n        int b = nextFree[pos];\n        if (a != -1) addd(a - base);\n        if (b != COORD_MAX + 1) addd(b - base);\n    };\n\n    addd(0);\n    addd(-1);\n    addd(1);\n    addd(-2);\n    addd(2);\n    addd(-3);\n    addd(3);\n    addd(lo);\n    addd(hi);\n    addd((lo + hi) / 2);\n\n    add_free_for_boundary(mn, mn);\n    add_free_for_boundary(mx, mx);\n\n    auto proc_around = [&](int v, int base) {\n        int pos = (int)(lower_bound(fishVals.begin(), fishVals.end(), v) - fishVals.begin());\n        for (int d = -4; d <= 4; d++) {\n            int idx = pos + d;\n            if (0 <= idx && idx < (int)fishVals.size()) add_from_target(fishVals[idx], base);\n        }\n    };\n\n    proc_around(mn, mn);\n    proc_around(mx, mx);\n\n    sort(res.begin(), res.end());\n    res.erase(unique(res.begin(), res.end()), res.end());\n    return res;\n}\n\nbool try_snap_variants(\n    Candidate& cur,\n    int& curScore,\n    CachedExactScorer& scorer,\n    const vector<char>& hasX,\n    const vector<char>& hasY,\n    const function<double()>& elapsed_ms,\n    double deadline_ms\n) {\n    if (elapsed_ms() > deadline_ms) return false;\n\n    bool changed = false;\n    vector<pair<bool,bool>> modes;\n    modes.push_back({true, true});\n    if ((int)cur.poly.size() <= 120) {\n        modes.push_back({true, false});\n        modes.push_back({false, true});\n    }\n\n    for (auto [ux, uy] : modes) {\n        if (elapsed_ms() > deadline_ms) break;\n        auto poly = snap_poly_lines_mode(cur.poly, hasX, hasY, ux, uy);\n        if (poly.empty()) continue;\n        Candidate cc = make_candidate(std::move(poly), cur.approx);\n        int sc = scorer.score(cc);\n        if (sc > curScore || (sc == curScore && cc.perim < cur.perim)) {\n            cur = std::move(cc);\n            curScore = sc;\n            changed = true;\n        }\n    }\n    return changed;\n}\n\nbool optimize_translate_once(\n    Candidate& cur,\n    int& curScore,\n    bool useX,\n    CachedExactScorer& scorer,\n    const vector<int>& fishVals,\n    const vector<int>& prevFree,\n    const vector<int>& nextFree,\n    const function<double()>& elapsed_ms,\n    double deadline_ms\n) {\n    if (elapsed_ms() > deadline_ms) return false;\n\n    int mn = useX ? cur.minx : cur.miny;\n    int mx = useX ? cur.maxx : cur.maxy;\n    int lo = -mn;\n    int hi = COORD_MAX - mx;\n    if (lo > hi) return false;\n\n    auto deltas = shift_candidate_values(fishVals, mn, mx, lo, hi, prevFree, nextFree);\n\n    int bestSc = curScore;\n    Candidate bestCand;\n    bool found = false;\n\n    for (int d : deltas) {\n        if (elapsed_ms() > deadline_ms) break;\n        if (d == 0) continue;\n\n        vector<Pt> poly = cur.poly;\n        if (useX) {\n            for (auto& p : poly) p.x += d;\n        } else {\n            for (auto& p : poly) p.y += d;\n        }\n        if (!basic_valid_poly(poly)) continue;\n\n        Candidate cc = make_candidate(std::move(poly), cur.approx);\n        int sc = scorer.score(cc);\n        if (sc > bestSc || (sc == bestSc && cc.perim < cur.perim)) {\n            bestSc = sc;\n            bestCand = std::move(cc);\n            found = true;\n        }\n    }\n\n    if (found) {\n        cur = std::move(bestCand);\n        curScore = bestSc;\n        return true;\n    }\n    return false;\n}\n\nbool optimize_axis_once(\n    Candidate& cur,\n    int& curScore,\n    bool useX,\n    CachedExactScorer& scorer,\n    const vector<int>& fishVals,\n    const vector<int>& prevFree,\n    const vector<int>& nextFree,\n    const function<double()>& elapsed_ms,\n    double deadline_ms\n) {\n    if (elapsed_ms() > deadline_ms) return false;\n\n    vector<int> levels, freq;\n    extract_axis_levels(cur, useX, levels, freq);\n    if ((int)levels.size() <= 1) return false;\n\n    int K = 6;\n    if ((int)cur.poly.size() <= 80) K = 10;\n    else if ((int)cur.poly.size() <= 160) K = 8;\n\n    auto idxs = pick_level_indices(levels, freq, K);\n\n    for (int idx : idxs) {\n        if (elapsed_ms() > deadline_ms) return false;\n\n        int oldv = levels[idx];\n        int L = (idx == 0 ? 0 : levels[idx - 1] + 1);\n        int R = (idx + 1 == (int)levels.size() ? COORD_MAX : levels[idx + 1] - 1);\n        if (L > R) continue;\n\n        auto candVals = axis_candidate_values(fishVals, oldv, L, R, prevFree, nextFree);\n\n        int bestSc = curScore;\n        Candidate bestCand;\n        bool found = false;\n\n        for (int nv : candVals) {\n            if (elapsed_ms() > deadline_ms) break;\n            if (nv == oldv) continue;\n\n            vector<Pt> poly = cur.poly;\n            for (auto& p : poly) {\n                int& a = useX ? p.x : p.y;\n                if (a == oldv) a = nv;\n            }\n            if (!basic_valid_poly(poly)) continue;\n\n            Candidate cc = make_candidate(std::move(poly), cur.approx);\n            int sc = scorer.score(cc);\n\n            if (sc > bestSc || (sc == bestSc && cc.perim < cur.perim)) {\n                bestSc = sc;\n                bestCand = std::move(cc);\n                found = true;\n            }\n        }\n\n        if (found) {\n            cur = std::move(bestCand);\n            curScore = bestSc;\n            return true;\n        }\n    }\n\n    return false;\n}\n\npair<Candidate,int> local_optimize_candidate(\n    Candidate cur,\n    int curScore,\n    CachedExactScorer& scorer,\n    const vector<int>& fishXs,\n    const vector<int>& fishYs,\n    const vector<int>& prevFreeX,\n    const vector<int>& nextFreeX,\n    const vector<int>& prevFreeY,\n    const vector<int>& nextFreeY,\n    const vector<char>& hasX,\n    const vector<char>& hasY,\n    const function<double()>& elapsed_ms,\n    double deadline_ms,\n    int maxRounds\n) {\n    bool allowAxis = ((int)cur.poly.size() <= 260);\n\n    for (int round = 0; round < maxRounds; round++) {\n        if (elapsed_ms() > deadline_ms) break;\n        bool changed = false;\n\n        changed |= optimize_translate_once(cur, curScore, true, scorer, fishXs, prevFreeX, nextFreeX, elapsed_ms, deadline_ms);\n        if (elapsed_ms() > deadline_ms) break;\n        changed |= optimize_translate_once(cur, curScore, false, scorer, fishYs, prevFreeY, nextFreeY, elapsed_ms, deadline_ms);\n        if (elapsed_ms() > deadline_ms) break;\n\n        if (allowAxis) {\n            changed |= optimize_axis_once(cur, curScore, true, scorer, fishXs, prevFreeX, nextFreeX, elapsed_ms, deadline_ms);\n            if (elapsed_ms() > deadline_ms) break;\n            changed |= optimize_axis_once(cur, curScore, false, scorer, fishYs, prevFreeY, nextFreeY, elapsed_ms, deadline_ms);\n            if (elapsed_ms() > deadline_ms) break;\n        }\n\n        changed |= try_snap_variants(cur, curScore, scorer, hasX, hasY, elapsed_ms, deadline_ms);\n\n        if (!changed) break;\n    }\n    return {cur, curScore};\n}\n\nvoid update_elite(vector<pair<int,Candidate>>& elite, int sc, const Candidate& c) {\n    for (auto& e : elite) {\n        if (e.second.hash == c.hash) {\n            if (sc > e.first) e.first = sc;\n            return;\n        }\n    }\n    elite.push_back({sc, c});\n    sort(elite.begin(), elite.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        if (a.second.perim != b.second.perim) return a.second.perim < b.second.perim;\n        return a.second.poly.size() < b.second.poly.size();\n    });\n    if ((int)elite.size() > 5) elite.resize(5);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto t0 = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, std::milli>(chrono::steady_clock::now() - t0).count();\n    };\n\n    int N;\n    cin >> N;\n\n    vector<Pt> macks(N), sards(N);\n    unordered_set<long long> allPts;\n    allPts.reserve((size_t)2 * N * 2);\n\n    vector<char> hasX(COORD_MAX + 1, 0), hasY(COORD_MAX + 1, 0);\n    vector<int> fishXs, fishYs;\n    fishXs.reserve(2 * N);\n    fishYs.reserve(2 * N);\n\n    for (int i = 0; i < N; i++) {\n        cin >> macks[i].x >> macks[i].y;\n        allPts.insert(1LL * macks[i].x * (COORD_MAX + 1) + macks[i].y);\n        hasX[macks[i].x] = 1;\n        hasY[macks[i].y] = 1;\n        fishXs.push_back(macks[i].x);\n        fishYs.push_back(macks[i].y);\n    }\n    for (int i = 0; i < N; i++) {\n        cin >> sards[i].x >> sards[i].y;\n        allPts.insert(1LL * sards[i].x * (COORD_MAX + 1) + sards[i].y);\n        hasX[sards[i].x] = 1;\n        hasY[sards[i].y] = 1;\n        fishXs.push_back(sards[i].x);\n        fishYs.push_back(sards[i].y);\n    }\n\n    sort(fishXs.begin(), fishXs.end());\n    fishXs.erase(unique(fishXs.begin(), fishXs.end()), fishXs.end());\n    sort(fishYs.begin(), fishYs.end());\n    fishYs.erase(unique(fishYs.begin(), fishYs.end()), fishYs.end());\n\n    vector<int> prevFreeX, nextFreeX, prevFreeY, nextFreeY;\n    build_free_arrays(hasX, prevFreeX, nextFreeX);\n    build_free_arrays(hasY, prevFreeY, nextFreeY);\n\n    FishEnv env;\n    env.pts.reserve(2 * N);\n    env.sgn.reserve(2 * N);\n    env.byX.assign(COORD_MAX + 1, {});\n    env.byY.assign(COORD_MAX + 1, {});\n\n    for (int i = 0; i < N; i++) {\n        int idx = (int)env.pts.size();\n        env.pts.push_back(macks[i]);\n        env.sgn.push_back(+1);\n        env.byX[macks[i].x].push_back(idx);\n        env.byY[macks[i].y].push_back(idx);\n    }\n    for (int i = 0; i < N; i++) {\n        int idx = (int)env.pts.size();\n        env.pts.push_back(sards[i]);\n        env.sgn.push_back(-1);\n        env.byX[sards[i].x].push_back(idx);\n        env.byY[sards[i].y].push_back(idx);\n    }\n\n    env.ordY.resize(env.pts.size());\n    iota(env.ordY.begin(), env.ordY.end(), 0);\n    sort(env.ordY.begin(), env.ordY.end(), [&](int a, int b) {\n        if (env.pts[a].y != env.pts[b].y) return env.pts[a].y < env.pts[b].y;\n        return env.pts[a].x < env.pts[b].x;\n    });\n\n    vector<Candidate> cands;\n    cands.reserve(2800);\n    unordered_set<uint64_t> seenHash;\n    seenHash.reserve(14000);\n\n    {\n        int G = 800;\n        vector<pair<int,int>> shifts = {{0, 0}, {G / 2, G / 2}};\n        for (auto [sx, sy] : shifts) {\n            if (elapsed_ms() > 350.0) break;\n            GridData gd = build_grid(macks, sards, G, sx, sy);\n\n            {\n                auto occ = best_rectangle_region(gd);\n                try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n            }\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                for (int i = 0; i < gd.W * gd.H; i++) if (gd.w[i] > 0) sel[i] = 1;\n                process_selection_light(gd, sel, cands, seenHash, hasX, hasY);\n            }\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 2) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection_light(gd, sel, cands, seenHash, hasX, hasY);\n            }\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 3) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection_light(gd, sel, cands, seenHash, hasX, hasY);\n            }\n        }\n    }\n\n    vector<int> Gs = {1000, 1400, 1800, 2300, 3000};\n\n    bool stopGen = false;\n    for (int G : Gs) {\n        vector<pair<int,int>> shifts = {\n            {0, 0},\n            {0, G / 2},\n            {G / 2, 0},\n            {G / 2, G / 2}\n        };\n\n        vector<int> lambdas;\n        if (G == 1000) lambdas = {1};\n        else if (G <= 1800) lambdas = {1, 2};\n        else lambdas = {1, 2, 3};\n\n        for (auto [sx, sy] : shifts) {\n            if (elapsed_ms() > 1700.0) { stopGen = true; break; }\n\n            GridData gd = build_grid(macks, sards, G, sx, sy);\n\n            {\n                auto occ = best_rectangle_region(gd);\n                try_add_candidate(cands, seenHash, gd, occ, hasX, hasY);\n            }\n\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                for (int i = 0; i < gd.W * gd.H; i++) if (gd.w[i] > 0) sel[i] = 1;\n                process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 2) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            if (G <= 1400) {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool any = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 3) {\n                        sel[i] = 1;\n                        any = true;\n                    }\n                }\n                if (any) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            if (G >= 2300) {\n                vector<char> sel(gd.W * gd.H, 0);\n                bool anyPos = false;\n                for (int i = 0; i < gd.W * gd.H; i++) {\n                    if (gd.w[i] >= 0) sel[i] = 1;\n                    if (gd.w[i] > 0) anyPos = true;\n                }\n                if (anyPos) process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n\n            for (int lambda : lambdas) {\n                if (elapsed_ms() > 1770.0) { stopGen = true; break; }\n                auto sel = graph_cut_select(gd, lambda);\n                process_selection(gd, sel, cands, seenHash, hasX, hasY);\n            }\n            if (stopGen) break;\n        }\n        if (stopGen) break;\n    }\n\n    Candidate best = make_candidate(find_empty_square(allPts), 0);\n    CachedExactScorer scorer(env);\n    int bestScore = scorer.score(best);\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.approx != b.approx) return a.approx > b.approx;\n        if (a.perim != b.perim) return a.perim < b.perim;\n        return a.poly.size() < b.poly.size();\n    });\n\n    vector<pair<int,Candidate>> elite;\n    update_elite(elite, bestScore, best);\n\n    for (const auto& c : cands) {\n        if (elapsed_ms() > 1978.0) break;\n        int sc = scorer.score(c);\n        if (sc > bestScore) {\n            bestScore = sc;\n            best = c;\n        }\n        update_elite(elite, sc, c);\n    }\n\n    sort(elite.begin(), elite.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        if (a.second.perim != b.second.perim) return a.second.perim < b.second.perim;\n        return a.second.poly.size() < b.second.poly.size();\n    });\n\n    for (int i = 0; i < (int)elite.size(); i++) {\n        if (elapsed_ms() > 1993.5) break;\n        int rounds = (i == 0 ? 4 : (i == 1 ? 2 : 1));\n        auto [cand2, sc2] = local_optimize_candidate(\n            elite[i].second, elite[i].first, scorer,\n            fishXs, fishYs,\n            prevFreeX, nextFreeX, prevFreeY, nextFreeY,\n            hasX, hasY,\n            elapsed_ms, 1993.5, rounds\n        );\n        if (sc2 > bestScore) {\n            bestScore = sc2;\n            best = std::move(cand2);\n        }\n    }\n\n    cout << best.poly.size() << '\\n';\n    for (auto& p : best.poly) {\n        cout << p.x << ' ' << p.y << '\\n';\n    }\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Dim {\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 baseScore = 1e100;\n    double robustScore = 1e100;\n    uint64_t hash = 0;\n};\n\nstruct ShelfSol {\n    char dir = 'L'; // 'L': row shelves, 'U': column shelves\n    vector<unsigned char> used, rot, brk; // if used[i], brk[i]=1 means starts new group\n    double score = 1e100;\n};\n\nstatic uint64_t splitmix64(uint64_t x) {\n    x += 0x9e3779b97f4a7c15ULL;\n    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL;\n    return x ^ (x >> 31);\n}\n\nstatic uint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    h ^= splitmix64((uint64_t)ops.size());\n    for (const auto& op : ops) {\n        uint64_t v = 0;\n        v ^= (uint64_t)(op.p + 1) * 1000003ULL;\n        v ^= (uint64_t)(op.r + 7) * 10007ULL;\n        v ^= (uint64_t)(unsigned char)(op.d) * 911382323ULL;\n        v ^= (uint64_t)(op.b + 2) * 972663749ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\nstatic bool overlap1D(double l1, double r1, double l2, double r2) {\n    const double EPS = 1e-9;\n    return max(l1, l2) + EPS < min(r1, r2);\n}\n\nstatic double exact_score(const vector<Dim>& dims, const vector<Op>& ops) {\n    int N = (int)dims.size();\n    vector<double> x1(N, 0), y1(N, 0), x2(N, 0), y2(N, 0);\n    vector<char> placed(N, 0), used(N, 0);\n\n    double W = 0, H = 0;\n\n    for (const auto& op : ops) {\n        int p = op.p;\n        double w = op.r ? dims[p].h : dims[p].w;\n        double h = op.r ? dims[p].w : dims[p].h;\n\n        double x = 0, y = 0;\n\n        if (op.d == 'U') {\n            x = (op.b == -1 ? 0.0 : x2[op.b]);\n            y = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(x, x + w, x1[j], x2[j])) {\n                    y = max(y, y2[j]);\n                }\n            }\n        } else {\n            y = (op.b == -1 ? 0.0 : y2[op.b]);\n            x = 0.0;\n            for (int j = 0; j < N; j++) if (placed[j]) {\n                if (overlap1D(y, y + h, y1[j], y2[j])) {\n                    x = max(x, x2[j]);\n                }\n            }\n        }\n\n        x1[p] = x; y1[p] = y;\n        x2[p] = x + w; y2[p] = y + h;\n        placed[p] = used[p] = 1;\n\n        W = max(W, x2[p]);\n        H = max(H, y2[p]);\n    }\n\n    double penalty = 0.0;\n    for (int i = 0; i < N; i++) {\n        if (!used[i]) penalty += dims[i].w + dims[i].h;\n    }\n    return W + H + penalty;\n}\n\nstatic pair<long long, long long> query_ops(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const auto& op : ops) {\n        cout << op.p << ' ' << op.r << ' ' << op.d << ' ' << op.b << '\\n';\n    }\n    cout.flush();\n\n    long long W, H;\n    if (!(cin >> W >> H)) exit(0);\n    if (W < 0 || H < 0) exit(0);\n    return {W, H};\n}\n\nstatic vector<Op> make_line_ops(const vector<int>& ids, char dir, int rot = 0) {\n    vector<Op> ops;\n    ops.reserve(ids.size());\n    for (int x : ids) ops.push_back({x, rot, dir, -1});\n    return ops;\n}\n\nstatic vector<Op> make_all_line_ops(int N, char dir, int rot = 0) {\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    return make_line_ops(ids, dir, rot);\n}\n\nstatic vector<int> top_k_indices(const vector<double>& vals, int K) {\n    int N = (int)vals.size();\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n    if (K <= 0) return {};\n    if (K >= N) return ids;\n    nth_element(ids.begin(), ids.begin() + K, ids.end(), [&](int a, int b) {\n        return vals[a] > vals[b];\n    });\n    ids.resize(K);\n    sort(ids.begin(), ids.end());\n    return ids;\n}\n\nstatic vector<double> correct_groupwise(\n    const vector<double>& y,\n    double totalM, double tauTotal,\n    const vector<int>* subset,\n    double subsetM, double tauSubset\n) {\n    int N = (int)y.size();\n    vector<double> x(N);\n    double Sy = 0.0;\n    for (double v : y) Sy += v;\n\n    if (subset == nullptr || subset->empty() || (int)subset->size() == N || subsetM < 0) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    vector<char> inS(N, 0);\n    double SS = 0.0;\n    for (int idx : *subset) {\n        inS[idx] = 1;\n        SS += y[idx];\n    }\n    double nS = (double)subset->size();\n\n    double d0 = Sy - totalM;\n    double d1 = SS - subsetM;\n\n    double a11 = N + tauTotal;\n    double a12 = nS;\n    double a21 = nS;\n    double a22 = nS + tauSubset;\n    double det = a11 * a22 - a12 * a21;\n\n    if (fabs(det) < 1e-12) {\n        double A = (Sy - totalM) / (N + tauTotal);\n        for (int i = 0; i < N; i++) x[i] = max(1.0, y[i] - A);\n        return x;\n    }\n\n    double A = (d0 * a22 - d1 * a12) / det;\n    double B = (a11 * d1 - a21 * d0) / det;\n\n    for (int i = 0; i < N; i++) {\n        double v = y[i] - A - (inS[i] ? B : 0.0);\n        x[i] = max(1.0, v);\n    }\n    return x;\n}\n\nstatic vector<double> sample_cond_1d(\n    const vector<double>& obs,\n    double totalM, double tauTotal,\n    const vector<int>* subset,\n    double subsetM, double tauSubset,\n    double sigma,\n    double alpha,\n    mt19937_64& rng\n) {\n    static normal_distribution<double> nd(0.0, 1.0);\n    vector<double> y = obs;\n    for (double& v : y) v += nd(rng) * alpha * sigma;\n    return correct_groupwise(y, totalM, tauTotal, subset, subsetM, tauSubset);\n}\n\nstatic vector<Dim> sample_world_conditioned(\n    const vector<double>& obsW,\n    const vector<double>& obsH,\n    double totalW, double tauW,\n    const vector<int>* subsetW, double subsetWM, double tauSW,\n    double totalH, double tauH,\n    const vector<int>* subsetH, double subsetHM, double tauSH,\n    double sigma,\n    double alpha,\n    mt19937_64& rng\n) {\n    int N = (int)obsW.size();\n    vector<double> sw = sample_cond_1d(obsW, totalW, tauW, subsetW, subsetWM, tauSW, sigma, alpha, rng);\n    vector<double> sh = sample_cond_1d(obsH, totalH, tauH, subsetH, subsetHM, tauSH, sigma, alpha, rng);\n    vector<Dim> out(N);\n    for (int i = 0; i < N; i++) out[i] = {sw[i], sh[i]};\n    return out;\n}\n\nstatic inline void get_ab(const Dim& d, char dir, int rot, double& a, double& b) {\n    if (dir == 'L') {\n        a = rot ? d.h : d.w;\n        b = rot ? d.w : d.h;\n    } else {\n        a = rot ? d.w : d.h;\n        b = rot ? d.h : d.w;\n    }\n}\n\nstatic inline double metric_b(const Dim& d, char dir, int rot) {\n    if (dir == 'L') return rot ? d.w : d.h;\n    return rot ? d.h : d.w;\n}\n\nstatic void normalize_shelf(ShelfSol& s) {\n    int N = (int)s.used.size();\n    for (int i = 0; i < N; i++) if (!s.used[i]) s.brk[i] = 0;\n    int first = -1;\n    for (int i = 0; i < N; i++) if (s.used[i]) {\n        first = i;\n        break;\n    }\n    if (first != -1) s.brk[first] = 1;\n}\n\nstatic double shelf_score_fast(const vector<Dim>& dims, const ShelfSol& s) {\n    int N = (int)dims.size();\n    double pen = 0.0;\n    double maxA = 0.0, sumB = 0.0;\n    double curA = 0.0, curB = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) {\n            pen += dims[i].w + dims[i].h;\n            continue;\n        }\n        double a, b;\n        get_ab(dims[i], s.dir, s.rot[i], a, b);\n\n        if (!active || s.brk[i]) {\n            if (active) {\n                maxA = max(maxA, curA);\n                sumB += curB;\n            }\n            curA = a;\n            curB = b;\n            active = true;\n        } else {\n            curA += a;\n            curB = max(curB, b);\n        }\n    }\n\n    if (active) {\n        maxA = max(maxA, curA);\n        sumB += curB;\n    }\n    return pen + maxA + sumB;\n}\n\nstatic double shelf_score_multi(const vector<vector<Dim>>& worlds, const ShelfSol& s) {\n    double sum = 0.0, mx = -1e100;\n    for (const auto& w : worlds) {\n        double sc = shelf_score_fast(w, s);\n        sum += sc;\n        mx = max(mx, sc);\n    }\n    double mean = sum / worlds.size();\n    return mean + 0.05 * (mx - mean);\n}\n\nstatic Candidate shelf_to_candidate(const vector<Dim>& base, const ShelfSol& s) {\n    int N = (int)base.size();\n\n    vector<vector<pair<int,int>>> groups;\n    bool active = false;\n    for (int i = 0; i < N; i++) {\n        if (!s.used[i]) continue;\n        if (!active || s.brk[i]) {\n            groups.emplace_back();\n            active = true;\n        }\n        groups.back().push_back({i, (int)s.rot[i]});\n    }\n\n    vector<int> reps;\n    reps.reserve(groups.size());\n\n    for (auto& g : groups) {\n        int bestIdx = g[0].first;\n        double bestM = metric_b(base[g[0].first], s.dir, g[0].second);\n        for (auto [idx, r] : g) {\n            double m = metric_b(base[idx], s.dir, r);\n            if (m > bestM) {\n                bestM = m;\n                bestIdx = idx;\n            }\n        }\n        reps.push_back(bestIdx);\n    }\n\n    vector<Op> ops;\n    for (int gi = 0; gi < (int)groups.size(); gi++) {\n        int bref = (gi == 0 ? -1 : reps[gi - 1]);\n        for (auto [idx, r] : groups[gi]) {\n            ops.push_back({idx, r, s.dir, bref});\n        }\n    }\n\n    Candidate c;\n    c.ops = move(ops);\n    c.baseScore = exact_score(base, c.ops);\n    c.hash = hash_ops(c.ops);\n    return c;\n}\n\nstatic ShelfSol candidate_to_shelf(const Candidate& c, int N) {\n    ShelfSol s;\n    s.dir = c.ops.empty() ? 'L' : c.ops[0].d;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool first = true;\n    int curb = INT_MIN;\n    for (const auto& op : c.ops) {\n        s.used[op.p] = 1;\n        s.rot[op.p] = (unsigned char)op.r;\n        if (first || op.b != curb) {\n            s.brk[op.p] = 1;\n            curb = op.b;\n            first = false;\n        }\n    }\n    normalize_shelf(s);\n    return s;\n}\n\nstatic double total_area(const vector<Dim>& dims) {\n    long double s = 0;\n    for (auto& d : dims) s += (long double)d.w * d.h;\n    return (double)s;\n}\n\nstruct Node {\n    int parent = -1;\n    unsigned char act = 0; // 0=skip, 1=continue/start, 2=new group\n    unsigned char rot = 0;\n    double maxDoneA = 0;\n    double sumDoneB = 0;\n    double curA = 0;\n    double curB = 0;\n    double pen = 0;\n    double eval = 0;\n};\n\nstatic inline double node_exact_score(const Node& s) {\n    return s.pen + max(s.maxDoneA, s.curA) + s.sumDoneB + s.curB;\n}\n\nstatic Candidate beam_shelf(\n    const vector<Dim>& sample,\n    const vector<Dim>& base,\n    char dir,\n    double targetA,\n    int beamWidth,\n    double omitMul\n) {\n    int N = (int)sample.size();\n    vector<double> a0(N), b0(N), a1(N), b1(N), remArea(N + 1);\n\n    for (int i = 0; i < N; i++) {\n        double a, b;\n        get_ab(sample[i], dir, 0, a, b);\n        a0[i] = a; b0[i] = b;\n        get_ab(sample[i], dir, 1, a, b);\n        a1[i] = a; b1[i] = b;\n    }\n\n    remArea[N] = 0.0;\n    for (int i = N - 1; i >= 0; i--) {\n        remArea[i] = remArea[i + 1] + sample[i].w * sample[i].h;\n    }\n\n    auto calc_eval = [&](double maxDoneA, double sumDoneB, double curA, double curB, double pen, int nexti) -> double {\n        double nowA = max(maxDoneA, curA);\n        double assumedA = max(nowA, targetA);\n        if (assumedA < 1.0) assumedA = 1.0;\n        return pen + assumedA + sumDoneB + curB + remArea[nexti] / assumedA;\n    };\n\n    vector<Node> nodes;\n    nodes.reserve(1 + (size_t)N * beamWidth * 5 + 16);\n    nodes.push_back(Node());\n    nodes[0].eval = calc_eval(0, 0, 0, 0, 0, 0);\n\n    vector<int> beam, nxt;\n    beam.push_back(0);\n\n    auto cmp = [&](int x, int y) {\n        if (nodes[x].eval != nodes[y].eval) return nodes[x].eval < nodes[y].eval;\n        return node_exact_score(nodes[x]) < node_exact_score(nodes[y]);\n    };\n\n    for (int i = 0; i < N; i++) {\n        nxt.clear();\n        nxt.reserve((size_t)beam.size() * 5 + 8);\n\n        for (int id : beam) {\n            const Node& s = nodes[id];\n\n            {\n                Node t = s;\n                t.parent = id;\n                t.act = 0;\n                t.rot = 0;\n                t.pen = s.pen + omitMul * (sample[i].w + sample[i].h);\n                t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                nodes.push_back(t);\n                nxt.push_back((int)nodes.size() - 1);\n            }\n\n            for (int r = 0; r < 2; r++) {\n                double a = (r ? a1[i] : a0[i]);\n                double b = (r ? b1[i] : b0[i]);\n\n                if (s.curA == 0.0 && s.curB == 0.0 && s.maxDoneA == 0.0 && s.sumDoneB == 0.0) {\n                    Node t;\n                    t.parent = id;\n                    t.act = 1;\n                    t.rot = (unsigned char)r;\n                    t.curA = a;\n                    t.curB = b;\n                    t.pen = s.pen;\n                    t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                    nodes.push_back(t);\n                    nxt.push_back((int)nodes.size() - 1);\n                } else {\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 1;\n                        t.rot = (unsigned char)r;\n                        t.curA = s.curA + a;\n                        t.curB = max(s.curB, b);\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                    {\n                        Node t = s;\n                        t.parent = id;\n                        t.act = 2;\n                        t.rot = (unsigned char)r;\n                        t.maxDoneA = max(s.maxDoneA, s.curA);\n                        t.sumDoneB = s.sumDoneB + s.curB;\n                        t.curA = a;\n                        t.curB = b;\n                        t.eval = calc_eval(t.maxDoneA, t.sumDoneB, t.curA, t.curB, t.pen, i + 1);\n                        nodes.push_back(t);\n                        nxt.push_back((int)nodes.size() - 1);\n                    }\n                }\n            }\n        }\n\n        if ((int)nxt.size() > beamWidth) {\n            nth_element(nxt.begin(), nxt.begin() + beamWidth, nxt.end(), cmp);\n            nxt.resize(beamWidth);\n        }\n        sort(nxt.begin(), nxt.end(), cmp);\n        beam.swap(nxt);\n    }\n\n    int bestId = beam[0];\n    double bestExact = node_exact_score(nodes[bestId]);\n    for (int id : beam) {\n        double sc = node_exact_score(nodes[id]);\n        if (sc < bestExact) {\n            bestExact = sc;\n            bestId = id;\n        }\n    }\n\n    vector<int> act(N, 0), rot(N, 0);\n    int cur = bestId;\n    for (int i = N - 1; i >= 0; i--) {\n        act[i] = nodes[cur].act;\n        rot[i] = nodes[cur].rot;\n        cur = nodes[cur].parent;\n    }\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    bool started = false;\n    for (int i = 0; i < N; i++) {\n        if (act[i] == 0) continue;\n        s.used[i] = 1;\n        s.rot[i] = (unsigned char)rot[i];\n        if (!started || act[i] == 2) {\n            s.brk[i] = 1;\n            started = true;\n        }\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    return shelf_to_candidate(base, s);\n}\n\nstatic ShelfSol random_seed_shelf(const vector<Dim>& base, char dir, double targetA, mt19937_64& rng) {\n    int N = (int)base.size();\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    ShelfSol s;\n    s.dir = dir;\n    s.used.assign(N, 0);\n    s.rot.assign(N, 0);\n    s.brk.assign(N, 0);\n\n    double curA = 0.0;\n    bool active = false;\n\n    for (int i = 0; i < N; i++) {\n        if (ur(rng) < 0.03) continue;\n\n        double a0, b0, a1, b1;\n        get_ab(base[i], dir, 0, a0, b0);\n        get_ab(base[i], dir, 1, a1, b1);\n\n        double fit0 = fabs((active ? curA : 0.0) + a0 - targetA) + 0.30 * b0;\n        double fit1 = fabs((active ? curA : 0.0) + a1 - targetA) + 0.30 * b1;\n        int r = (fit1 < fit0 ? 1 : 0);\n\n        double a = (r ? a1 : a0);\n        bool newg = !active || curA + a > targetA * (0.85 + 0.40 * ur(rng));\n\n        s.used[i] = 1;\n        s.rot[i] = (unsigned char)r;\n        if (newg) {\n            s.brk[i] = 1;\n            curA = a;\n            active = true;\n        } else {\n            curA += a;\n        }\n    }\n\n    if (!active) {\n        int i = (int)(rng() % N);\n        s.used[i] = 1;\n        s.rot[i] = (unsigned char)(rng() & 1);\n        s.brk[i] = 1;\n    }\n    normalize_shelf(s);\n    s.score = shelf_score_fast(base, s);\n    return s;\n}\n\nstatic void mutate_once(ShelfSol& s, mt19937_64& rng) {\n    int N = (int)s.used.size();\n    int typ = (int)(rng() % 100);\n    int i = (int)(rng() % N);\n\n    if (typ < 40) {\n        if (s.used[i]) {\n            s.rot[i] ^= 1;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else if (typ < 75) {\n        if (s.used[i]) {\n            s.used[i] = 0;\n            s.brk[i] = 0;\n        } else {\n            s.used[i] = 1;\n            s.rot[i] = (unsigned char)(rng() & 1);\n            s.brk[i] = (unsigned char)(rng() % 2);\n        }\n    } else {\n        if (s.used[i]) s.brk[i] ^= 1;\n    }\n}\n\nstatic ShelfSol greedy_polish(const vector<vector<Dim>>& worlds, ShelfSol s) {\n    int N = (int)s.used.size();\n    normalize_shelf(s);\n    double cur = shelf_score_multi(worlds, s);\n\n    for (int round = 0; round < 3; round++) {\n        bool improved = false;\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.rot[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_multi(worlds, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) if (s.used[i]) {\n            ShelfSol t = s;\n            t.brk[i] ^= 1;\n            normalize_shelf(t);\n            double sc = shelf_score_multi(worlds, t);\n            if (sc + 1e-9 < cur) {\n                s = move(t);\n                cur = sc;\n                improved = true;\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            if (s.used[i]) {\n                ShelfSol t = s;\n                t.used[i] = 0;\n                t.brk[i] = 0;\n                normalize_shelf(t);\n                double sc = shelf_score_multi(worlds, t);\n                if (sc + 1e-9 < cur) {\n                    s = move(t);\n                    cur = sc;\n                    improved = true;\n                }\n            } else {\n                double bestSc = cur;\n                ShelfSol bestT = s;\n                for (int r = 0; r < 2; r++) {\n                    for (int b = 0; b < 2; b++) {\n                        ShelfSol t = s;\n                        t.used[i] = 1;\n                        t.rot[i] = (unsigned char)r;\n                        t.brk[i] = (unsigned char)b;\n                        normalize_shelf(t);\n                        double sc = shelf_score_multi(worlds, t);\n                        if (sc + 1e-9 < bestSc) {\n                            bestSc = sc;\n                            bestT = move(t);\n                        }\n                    }\n                }\n                if (bestSc + 1e-9 < cur) {\n                    s = move(bestT);\n                    cur = bestSc;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    s.score = cur;\n    return s;\n}\n\nstatic ShelfSol local_search(\n    const vector<vector<Dim>>& worlds,\n    ShelfSol seed,\n    mt19937_64& rng,\n    int iterations,\n    chrono::steady_clock::time_point deadline\n) {\n    normalize_shelf(seed);\n    seed.score = shelf_score_multi(worlds, seed);\n\n    ShelfSol cur = seed, best = seed;\n    double curSc = seed.score, bestSc = seed.score;\n    uniform_real_distribution<double> ur(0.0, 1.0);\n\n    for (int it = 0; it < iterations; it++) {\n        if ((it & 255) == 0) {\n            if (chrono::steady_clock::now() >= deadline) break;\n        }\n\n        ShelfSol nxt = cur;\n        int moves = ((rng() % 5) == 0 ? 2 : 1);\n        for (int k = 0; k < moves; k++) mutate_once(nxt, rng);\n        normalize_shelf(nxt);\n        double sc = shelf_score_multi(worlds, nxt);\n\n        double prog = (double)it / max(1, iterations - 1);\n        double temp = 25000.0 * pow(0.002, prog) + 1.0;\n\n        if (sc < curSc || ur(rng) < exp((curSc - sc) / temp)) {\n            cur = move(nxt);\n            curSc = sc;\n            if (curSc < bestSc) {\n                best = cur;\n                bestSc = curSc;\n            }\n        }\n    }\n\n    best.score = bestSc;\n    best = greedy_polish(worlds, best);\n    return best;\n}\n\nstatic double robust_eval_candidate(const Candidate& cand, const vector<vector<Dim>>& worlds) {\n    double sum = 0.0, mx = -1e100;\n    for (const auto& w : worlds) {\n        double sc = exact_score(w, cand.ops);\n        sum += sc;\n        mx = max(mx, sc);\n    }\n    double mean = sum / worlds.size();\n    return mean + 0.08 * (mx - mean);\n}\n\nstatic vector<Candidate> generate_candidates(\n    const vector<Dim>& base,\n    const vector<vector<Dim>>& searchWorlds,\n    const vector<vector<Dim>>& rankWorlds,\n    int remainingTurns,\n    mt19937_64& rng,\n    chrono::steady_clock::time_point deadline\n) {\n    int N = (int)base.size();\n    double rootArea = sqrt(max(1.0, total_area(base)));\n\n    int beamDet = (N <= 60 ? 520 : 380);\n    int beamRnd = (N <= 60 ? 220 : 160);\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    auto add_cand = [&](Candidate cand) {\n        cand.hash = hash_ops(cand.ops);\n        if (seen.insert(cand.hash).second) {\n            pool.push_back(move(cand));\n        }\n    };\n\n    // Baseline straight-line candidates\n    for (int rot = 0; rot < 2; rot++) {\n        for (char dir : {'L', 'U'}) {\n            Candidate c;\n            c.ops = make_all_line_ops(N, dir, rot);\n            c.baseScore = exact_score(base, c.ops);\n            c.hash = hash_ops(c.ops);\n            add_cand(move(c));\n        }\n    }\n\n    vector<double> scales = {0.50, 0.63, 0.78, 0.92, 1.05, 1.20, 1.38, 1.60, 1.88};\n    vector<double> omits = {1.00, 1.12, 1.25, 1.40};\n\n    // Deterministic beams on base and a couple conditioned worlds.\n    int useWorlds = min((int)searchWorlds.size(), 3);\n    for (int wi = 0; wi < useWorlds; wi++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        const auto& w = searchWorlds[wi];\n        for (double sc : scales) {\n            add_cand(beam_shelf(w, base, 'L', rootArea * sc, beamDet, 1.15));\n            add_cand(beam_shelf(w, base, 'U', rootArea * sc, beamDet, 1.15));\n        }\n    }\n    for (double om : omits) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        add_cand(beam_shelf(base, base, 'L', rootArea, beamDet, om));\n        add_cand(beam_shelf(base, base, 'U', rootArea, beamDet, om));\n    }\n\n    // Randomized beams on conditioned worlds.\n    uniform_real_distribution<double> ul(log(0.45), log(2.20));\n    int randomBeamAttempts = min(120, remainingTurns + 50);\n    for (int it = 0; it < randomBeamAttempts; it++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        const auto& sample = searchWorlds[(int)(rng() % searchWorlds.size())];\n        double tgt = sqrt(max(1.0, total_area(sample))) * exp(ul(rng));\n        char dir = ((rng() & 1) ? 'L' : 'U');\n        double om = omits[(size_t)(rng() % omits.size())];\n        add_cand(beam_shelf(sample, base, dir, tgt, beamRnd, om));\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.baseScore < b.baseScore;\n    });\n\n    // Local search on top beam seeds.\n    vector<Candidate> enhanced = pool;\n    int topSeeds = min((int)pool.size(), 14);\n    for (int i = 0; i < topSeeds; i++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        ShelfSol s = candidate_to_shelf(pool[i], N);\n        int iters = (i < 8 ? 4500 : 2200);\n        ShelfSol best = local_search(searchWorlds, s, rng, iters, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    // Random seeds + local search.\n    for (int t = 0; t < 8; t++) {\n        if (chrono::steady_clock::now() >= deadline) break;\n        char dir = (t & 1) ? 'L' : 'U';\n        double sc = exp(ul(rng));\n        ShelfSol s = random_seed_shelf(base, dir, rootArea * sc, rng);\n        ShelfSol best = local_search(searchWorlds, s, rng, 1800, deadline);\n        Candidate c = shelf_to_candidate(base, best);\n        if (seen.insert(c.hash).second) enhanced.push_back(move(c));\n    }\n\n    for (auto& c : enhanced) {\n        c.robustScore = robust_eval_candidate(c, rankWorlds);\n    }\n\n    sort(enhanced.begin(), enhanced.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.robustScore != b.robustScore) return a.robustScore < b.robustScore;\n        return a.baseScore < b.baseScore;\n    });\n\n    if ((int)enhanced.size() > 260) enhanced.resize(260);\n    return enhanced;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    auto startTime = chrono::steady_clock::now();\n\n    int N, T, sigma_i;\n    cin >> N >> T >> sigma_i;\n    double sigma = sigma_i;\n\n    vector<Dim> obs(N);\n    for (int i = 0; i < N; i++) {\n        cin >> obs[i].w >> obs[i].h;\n    }\n\n    mt19937_64 rng(0x3141592653589793ULL);\n\n    vector<double> obsW(N), obsH(N);\n    for (int i = 0; i < N; i++) {\n        obsW[i] = obs[i].w;\n        obsH[i] = obs[i].h;\n    }\n\n    int usedTurns = 0;\n\n    // Calibration plan:\n    // always: total width, total height\n    // if T large enough: focused subset width/height\n    // if T larger: repeated totals via rotated full-line queries\n    bool useSubset = (T >= 20);\n    bool useRepeatTotals = (T >= 32);\n\n    int K = min(max(6, N / 4), 20);\n    vector<int> subsetW = top_k_indices(obsW, K);\n    vector<int> subsetH = top_k_indices(obsH, K);\n\n    vector<double> totalWidthMeasures, totalHeightMeasures;\n    double subsetWidthMeasure = -1.0, subsetHeightMeasure = -1.0;\n\n    // 1) total width by all-in-row, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 0));\n        (void)Hm;\n        totalWidthMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 2) total height by all-in-column, no rotation\n    {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 0));\n        (void)Wm;\n        totalHeightMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    // 3) focused width subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetW, 'L', 0));\n        (void)Hm;\n        subsetWidthMeasure = (double)Wm;\n        usedTurns++;\n    }\n\n    // 4) focused height subset\n    if (useSubset && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_line_ops(subsetH, 'U', 0));\n        (void)Wm;\n        subsetHeightMeasure = (double)Hm;\n        usedTurns++;\n    }\n\n    // 5) repeat total height via all-in-row, rotated\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'L', 1));\n        (void)Hm;\n        totalHeightMeasures.push_back((double)Wm);\n        usedTurns++;\n    }\n\n    // 6) repeat total width via all-in-column, rotated\n    if (useRepeatTotals && usedTurns < T) {\n        auto [Wm, Hm] = query_ops(make_all_line_ops(N, 'U', 1));\n        (void)Wm;\n        totalWidthMeasures.push_back((double)Hm);\n        usedTurns++;\n    }\n\n    int remainingTurns = T - usedTurns;\n    if (remainingTurns <= 0) return 0;\n\n    auto avg = [](const vector<double>& v) {\n        double s = 0.0;\n        for (double x : v) s += x;\n        return s / v.size();\n    };\n\n    double totalW = avg(totalWidthMeasures);\n    double totalH = avg(totalHeightMeasures);\n    double tauW = 1.0 / (double)totalWidthMeasures.size();\n    double tauH = 1.0 / (double)totalHeightMeasures.size();\n\n    vector<double> corrW = correct_groupwise(\n        obsW, totalW, tauW,\n        (subsetWidthMeasure >= 0 ? &subsetW : nullptr),\n        subsetWidthMeasure, 1.0\n    );\n    vector<double> corrH = correct_groupwise(\n        obsH, totalH, tauH,\n        (subsetHeightMeasure >= 0 ? &subsetH : nullptr),\n        subsetHeightMeasure, 1.0\n    );\n\n    vector<Dim> base(N);\n    for (int i = 0; i < N; i++) {\n        base[i].w = corrW[i];\n        base[i].h = corrH[i];\n    }\n\n    // Search worlds: moderate number for local search.\n    vector<vector<Dim>> searchWorlds;\n    searchWorlds.push_back(base);\n    for (double a : {0.70, 1.10, 1.50}) {\n        searchWorlds.push_back(sample_world_conditioned(\n            obsW, obsH,\n            totalW, tauW, (subsetWidthMeasure >= 0 ? &subsetW : nullptr), subsetWidthMeasure, 1.0,\n            totalH, tauH, (subsetHeightMeasure >= 0 ? &subsetH : nullptr), subsetHeightMeasure, 1.0,\n            sigma, a, rng\n        ));\n    }\n\n    // Ranking worlds: a bit wider.\n    vector<vector<Dim>> rankWorlds = searchWorlds;\n    rankWorlds.push_back(sample_world_conditioned(\n        obsW, obsH,\n        totalW, tauW, (subsetWidthMeasure >= 0 ? &subsetW : nullptr), subsetWidthMeasure, 1.0,\n        totalH, tauH, (subsetHeightMeasure >= 0 ? &subsetH : nullptr), subsetHeightMeasure, 1.0,\n        sigma, 0.45, rng\n    ));\n    rankWorlds.push_back(sample_world_conditioned(\n        obsW, obsH,\n        totalW, tauW, (subsetWidthMeasure >= 0 ? &subsetW : nullptr), subsetWidthMeasure, 1.0,\n        totalH, tauH, (subsetHeightMeasure >= 0 ? &subsetH : nullptr), subsetHeightMeasure, 1.0,\n        sigma, 1.90, rng\n    ));\n\n    auto deadline = startTime + chrono::milliseconds(2250);\n    auto pool = generate_candidates(base, searchWorlds, rankWorlds, remainingTurns, rng, deadline);\n    if (pool.empty()) {\n        pool.push_back(beam_shelf(base, base, 'L', sqrt(max(1.0, total_area(base))), 200, 1.2));\n    }\n\n    // Fixed schedule: mostly best candidates, but with some diversification.\n    int P = (int)pool.size();\n    vector<int> order;\n    vector<char> used(P, 0);\n\n    int cap = min(P, max(remainingTurns, min(P, remainingTurns * 3)));\n    int topTake = min(cap, max(5, remainingTurns * 2 / 3));\n\n    for (int i = 0; i < topTake; i++) {\n        if (!used[i]) {\n            used[i] = 1;\n            order.push_back(i);\n        }\n    }\n\n    int rem = remainingTurns - (int)order.size();\n    if (rem > 0 && cap > topTake) {\n        for (int s = 0; s < rem; s++) {\n            int idx = topTake + (int)((long long)(2 * s + 1) * (cap - topTake) / (2LL * rem));\n            idx = min(idx, cap - 1);\n            if (!used[idx]) {\n                used[idx] = 1;\n                order.push_back(idx);\n            }\n        }\n    }\n\n    for (int i = topTake; i < P && (int)order.size() < remainingTurns; i++) {\n        if (!used[i]) {\n            used[i] = 1;\n            order.push_back(i);\n        }\n    }\n\n    // Safe fallback: repeat best candidates if the pool is smaller than remaining turns.\n    while ((int)order.size() < remainingTurns) {\n        order.push_back(order.empty() ? 0 : order[(int)order.size() % max(1, min(P, 8))]);\n    }\n\n    for (int t = 0; t < remainingTurns; t++) {\n        auto resp = query_ops(pool[order[t]].ops);\n        (void)resp;\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    static constexpr int MAXN = 1000;\n\n    int N, M, H;\n    vector<int> A;\n    vector<pair<int, int>> edges;\n    vector<vector<int>> g;\n    vector<int> deg;\n    vector<int> X, Y;\n    vector<bitset<MAXN>> adjMat;\n\n    mt19937_64 rng{chrono::steady_clock::now().time_since_epoch().count()};\n    chrono::steady_clock::time_point start_time, deadline;\n\n    struct State {\n        vector<vector<int>> children;\n        vector<vector<int>> comps;\n        vector<int> roots;\n        vector<int> depth, tin, tout, compId;\n        vector<int> subtreeBeauty;\n        vector<int> maxAbsDepth;\n        long long score = 0;\n    };\n\n    struct Move {\n        long long gain = 0;\n        int par = -1;\n        int child = -1;\n        int parentSub = 0;\n        int parDepth = 0;\n        int parentDeg = 0;\n        int parentA = 0;\n        int childSub = 0;\n    };\n\n    struct DMove {\n        // type: 0 = raise, 1 = edge-swap\n        int type = -1;\n        int v = -1, u = -1;\n        int gain = 0;\n        int newDepth = -1;\n        int upA = 0, downA = 0;\n    };\n\n    bool time_up() const {\n        return chrono::steady_clock::now() >= deadline;\n    }\n\n    long long remaining_ms() const {\n        return chrono::duration_cast<chrono::milliseconds>(\n            deadline - chrono::steady_clock::now()\n        ).count();\n    }\n\n    double rand01() {\n        return uniform_real_distribution<double>(0.0, 1.0)(rng);\n    }\n\n    static bool betterMove(const Move& a, const Move& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.parDepth != b.parDepth) return a.parDepth > b.parDepth;\n        if (a.parentA != b.parentA) return a.parentA < b.parentA;\n        if (a.parentSub != b.parentSub) return a.parentSub < b.parentSub;\n        if (a.parentDeg != b.parentDeg) return a.parentDeg > b.parentDeg;\n        if (a.childSub != b.childSub) return a.childSub > b.childSub;\n        if (a.child != b.child) return a.child < b.child;\n        return a.par < b.par;\n    }\n\n    static bool betterDMove(const DMove& a, const DMove& b) {\n        if (a.gain != b.gain) return a.gain > b.gain;\n        if (a.newDepth != b.newDepth) return a.newDepth > b.newDepth;\n        if (a.type != b.type) return a.type < b.type; // prefer raise on tie\n        if (a.upA != b.upA) return a.upA > b.upA;\n        if (a.downA != b.downA) return a.downA < b.downA;\n        if (a.v != b.v) return a.v < b.v;\n        return a.u < b.u;\n    }\n\n    void rebuild(const vector<int>& parent, State& st) {\n        st.children.assign(N, {});\n        st.roots.clear();\n        st.depth.assign(N, 0);\n        st.tin.assign(N, 0);\n        st.tout.assign(N, 0);\n        st.compId.assign(N, -1);\n        st.subtreeBeauty.assign(N, 0);\n        st.maxAbsDepth.assign(N, 0);\n        st.comps.clear();\n        st.score = 1;\n\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] == -1) st.roots.push_back(v);\n            else st.children[parent[v]].push_back(v);\n        }\n\n        int timer = 0;\n        auto dfs = [&](auto&& self, int v, int comp) -> void {\n            st.compId[v] = comp;\n            st.tin[v] = timer++;\n            st.comps[comp].push_back(v);\n\n            st.subtreeBeauty[v] = A[v];\n            st.maxAbsDepth[v] = st.depth[v];\n            st.score += 1LL * (st.depth[v] + 1) * A[v];\n\n            for (int ch : st.children[v]) {\n                st.depth[ch] = st.depth[v] + 1;\n                self(self, ch, comp);\n                st.subtreeBeauty[v] += st.subtreeBeauty[ch];\n                st.maxAbsDepth[v] = max(st.maxAbsDepth[v], st.maxAbsDepth[ch]);\n            }\n            st.tout[v] = timer;\n        };\n\n        for (int r : st.roots) {\n            st.depth[r] = 0;\n            st.comps.push_back({});\n            dfs(dfs, r, (int)st.comps.size() - 1);\n        }\n    }\n\n    long long calcScore(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.score;\n    }\n\n    vector<int> depthFromParent(const vector<int>& parent) {\n        State st;\n        rebuild(parent, st);\n        return st.depth;\n    }\n\n    vector<int> parentFromDepth(const vector<int>& depth) {\n        vector<int> parent(N, -1);\n        vector<vector<int>> layers(H + 1);\n        for (int v = 0; v < N; ++v) layers[depth[v]].push_back(v);\n\n        for (int d = 1; d <= H; ++d) {\n            for (int v : layers[d]) {\n                int best = -1;\n                for (int to : g[v]) if (depth[to] == d - 1) {\n                    if (best == -1) best = to;\n                    else {\n                        if (A[to] != A[best]) best = (A[to] < A[best] ? to : best);\n                        else if (deg[to] != deg[best]) best = (deg[to] > deg[best] ? to : best);\n                        else if (to < best) best = to;\n                    }\n                }\n                parent[v] = best; // feasible depth assignments should give one\n            }\n        }\n        return parent;\n    }\n\n    bool makeCandidate(int par, int child, const State& st, Move& mv) {\n        int newDepth = st.depth[par] + 1;\n        if (newDepth > H) return false;\n        if (newDepth <= st.depth[child]) return false;\n\n        if (st.compId[par] == st.compId[child]) {\n            if (st.tin[child] <= st.tin[par] && st.tin[par] < st.tout[child]) {\n                return false;\n            }\n        }\n\n        int delta = newDepth - st.depth[child];\n        if (st.maxAbsDepth[child] + delta > H) return false;\n\n        mv.gain = 1LL * delta * st.subtreeBeauty[child];\n        if (mv.gain <= 0) return false;\n\n        mv.par = par;\n        mv.child = child;\n        mv.parentSub = st.subtreeBeauty[par];\n        mv.parDepth = st.depth[par];\n        mv.parentDeg = deg[par];\n        mv.parentA = A[par];\n        mv.childSub = st.subtreeBeauty[child];\n        return true;\n    }\n\n    bool findMoveDeterministic(const State& st, Move& best) {\n        bool found = false;\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (!found || betterMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            }\n        }\n        return found;\n    }\n\n    bool findMoveRandomized(const State& st, Move& chosen) {\n        vector<Move> cand;\n        cand.reserve(2 * M);\n        long long bestGain = 0;\n\n        for (auto [u, v] : edges) {\n            Move mv;\n            if (makeCandidate(u, v, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain * 100 >= bestGain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n            if (makeCandidate(v, u, st, mv)) {\n                if (mv.gain > bestGain) {\n                    bestGain = mv.gain;\n                    cand.clear();\n                    cand.push_back(mv);\n                } else if (mv.gain * 100 >= bestGain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n        }\n\n        if (bestGain <= 0) return false;\n        sort(cand.begin(), cand.end(), betterMove);\n        int k = min<int>(12, cand.size());\n        uniform_int_distribution<int> dist(0, k - 1);\n        chosen = cand[dist(rng)];\n        return true;\n    }\n\n    void hillClimb(vector<int>& parent, bool randomized) {\n        while (!time_up()) {\n            State st;\n            rebuild(parent, st);\n\n            Move mv;\n            bool ok = randomized ? findMoveRandomized(st, mv)\n                                 : findMoveDeterministic(st, mv);\n            if (!ok) break;\n            parent[mv.child] = mv.par;\n        }\n    }\n\n    bool rerootOptimize(vector<int>& parent) {\n        if (time_up()) return false;\n\n        State st;\n        rebuild(parent, st);\n\n        vector<vector<int>> treeAdj(N);\n        for (int v = 0; v < N; ++v) {\n            if (parent[v] != -1) {\n                treeAdj[v].push_back(parent[v]);\n                treeAdj[parent[v]].push_back(v);\n            }\n        }\n\n        vector<int> newParent = parent;\n        bool changedAny = false;\n\n        auto dfsScore = [&](auto&& self, int v, int p, int d, long long& sc, int& mx,\n                            const vector<vector<int>>& adj) -> void {\n            sc += 1LL * A[v] * d;\n            mx = max(mx, d);\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, d + 1, sc, mx, adj);\n            }\n        };\n\n        auto dfsOrient = [&](auto&& self, int v, int p,\n                             vector<int>& par, const vector<vector<int>>& adj) -> void {\n            par[v] = p;\n            for (int to : adj[v]) {\n                if (to == p) continue;\n                self(self, to, v, par, adj);\n            }\n        };\n\n        for (const auto& comp : st.comps) {\n            if (time_up()) return changedAny;\n            if (comp.size() <= 1) continue;\n\n            long long bestScore = LLONG_MIN;\n            int bestRoot = comp[0];\n\n            for (int r : comp) {\n                long long sc = 0;\n                int mx = 0;\n                dfsScore(dfsScore, r, -1, 0, sc, mx, treeAdj);\n                if (mx > H) continue;\n\n                bool better = false;\n                if (sc > bestScore) better = true;\n                else if (sc == bestScore) {\n                    if (A[r] < A[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] > deg[bestRoot]) better = true;\n                    else if (A[r] == A[bestRoot] && deg[r] == deg[bestRoot] && r < bestRoot) better = true;\n                }\n                if (better) {\n                    bestScore = sc;\n                    bestRoot = r;\n                }\n            }\n\n            if (bestScore == LLONG_MIN) continue;\n            dfsOrient(dfsOrient, bestRoot, -1, newParent, treeAdj);\n        }\n\n        if (newParent != parent) {\n            parent.swap(newParent);\n            changedAny = true;\n        }\n        return changedAny;\n    }\n\n    // -------- depth-label local search --------\n\n    bool canRaiseVertex(int v, const vector<int>& depth,\n                        const vector<array<int, 11>>& cnt) {\n        int d = depth[v];\n        if (d >= H) return false;\n        if (cnt[v][d] <= 0) return false;\n\n        for (int x : g[v]) {\n            if (depth[x] == d + 1 && cnt[x][d] == 1) return false;\n        }\n        return true;\n    }\n\n    bool canSwapEdge(int v, int u, const vector<int>& depth,\n                     const vector<array<int, 11>>& cnt) {\n        // require depth[v] = d, depth[u] = d+1\n        int d = depth[v];\n        if (d + 1 != depth[u]) return false;\n        if (A[v] <= A[u]) return false;\n        if (d >= H) return false;\n\n        // u moves to d, so it must have a neighbor at d-1 (unless d==0)\n        if (d > 0 && cnt[u][d - 1] == 0) return false;\n\n        // vertices at depth d+1 neighboring v must keep a depth-d support\n        for (int x : g[v]) {\n            if (x == u) continue;\n            if (depth[x] == d + 1) {\n                int newCnt = cnt[x][d] - 1 + (adjMat[u][x] ? 1 : 0);\n                if (newCnt <= 0) return false;\n            }\n        }\n\n        // vertices at depth d+2 neighboring u must keep a depth-(d+1) support\n        if (d + 2 <= H) {\n            for (int y : g[u]) {\n                if (depth[y] == d + 2) {\n                    int newCnt = cnt[y][d + 1] - 1 + (adjMat[v][y] ? 1 : 0);\n                    if (newCnt <= 0) return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    void applyRaise(int v, vector<int>& depth, vector<array<int, 11>>& cnt) {\n        int d = depth[v];\n        for (int x : g[v]) {\n            cnt[x][d]--;\n            cnt[x][d + 1]++;\n        }\n        depth[v]++;\n    }\n\n    void applySwap(int v, int u, vector<int>& depth, vector<array<int, 11>>& cnt) {\n        // depth[v] = d, depth[u] = d+1\n        int d = depth[v];\n\n        for (int x : g[v]) {\n            cnt[x][d]--;\n            cnt[x][d + 1]++;\n        }\n        for (int x : g[u]) {\n            cnt[x][d + 1]--;\n            cnt[x][d]++;\n        }\n        depth[v]++;\n        depth[u]--;\n    }\n\n    bool findDepthMove(const vector<int>& depth, const vector<array<int, 11>>& cnt,\n                       bool randomized, DMove& chosen) {\n        bool found = false;\n        DMove best;\n        vector<DMove> cand;\n        cand.reserve(N + M);\n\n        auto pushCand = [&](const DMove& mv) {\n            if (!randomized) {\n                if (!found || betterDMove(mv, best)) {\n                    best = mv;\n                    found = true;\n                }\n            } else {\n                if (!found || mv.gain > best.gain) {\n                    best = mv;\n                    cand.clear();\n                    cand.push_back(mv);\n                    found = true;\n                } else if (mv.gain * 100 >= best.gain * 95) {\n                    cand.push_back(mv);\n                }\n            }\n        };\n\n        for (int v = 0; v < N; ++v) {\n            if (canRaiseVertex(v, depth, cnt)) {\n                DMove mv;\n                mv.type = 0;\n                mv.v = v;\n                mv.u = -1;\n                mv.gain = A[v];\n                mv.newDepth = depth[v] + 1;\n                mv.upA = A[v];\n                mv.downA = 0;\n                pushCand(mv);\n            }\n        }\n\n        for (auto [a, b] : edges) {\n            if (depth[a] + 1 == depth[b]) {\n                if (canSwapEdge(a, b, depth, cnt)) {\n                    DMove mv;\n                    mv.type = 1;\n                    mv.v = a;\n                    mv.u = b;\n                    mv.gain = A[a] - A[b];\n                    mv.newDepth = depth[a] + 1;\n                    mv.upA = A[a];\n                    mv.downA = A[b];\n                    pushCand(mv);\n                }\n            } else if (depth[b] + 1 == depth[a]) {\n                if (canSwapEdge(b, a, depth, cnt)) {\n                    DMove mv;\n                    mv.type = 1;\n                    mv.v = b;\n                    mv.u = a;\n                    mv.gain = A[b] - A[a];\n                    mv.newDepth = depth[b] + 1;\n                    mv.upA = A[b];\n                    mv.downA = A[a];\n                    pushCand(mv);\n                }\n            }\n        }\n\n        if (!found) return false;\n\n        if (!randomized) {\n            chosen = best;\n            return true;\n        }\n\n        sort(cand.begin(), cand.end(), betterDMove);\n        int k = min<int>(16, cand.size());\n        uniform_int_distribution<int> dist(0, k - 1);\n        chosen = cand[dist(rng)];\n        return true;\n    }\n\n    void depthLocalSearch(vector<int>& depth, bool randomized) {\n        vector<array<int, 11>> cnt(N);\n        for (auto& ar : cnt) ar.fill(0);\n\n        for (auto [u, v] : edges) {\n            cnt[u][depth[v]]++;\n            cnt[v][depth[u]]++;\n        }\n\n        int iter = 0;\n        while (!time_up() && iter < 6000) {\n            DMove mv;\n            if (!findDepthMove(depth, cnt, randomized, mv)) break;\n            if (mv.type == 0) applyRaise(mv.v, depth, cnt);\n            else applySwap(mv.v, mv.u, depth, cnt);\n            ++iter;\n        }\n    }\n\n    // -------- initializers --------\n\n    vector<int> buildAllRoots() {\n        return vector<int>(N, -1);\n    }\n\n    vector<int> buildFromKey(const vector<double>& key) {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            if (key[a] != key[b]) return key[a] < key[b];\n            return a < b;\n        });\n\n        vector<int> parent(N, -1), depth(N, 0);\n        vector<char> done(N, 0);\n\n        auto betterPar = [&](int x, int y) {\n            if (y == -1) return true;\n            if (depth[x] != depth[y]) return depth[x] > depth[y];\n            if (A[x] != A[y]) return A[x] < A[y];\n            if (deg[x] != deg[y]) return deg[x] > deg[y];\n            return x < y;\n        };\n\n        for (int v : ord) {\n            int bestPar = -1;\n            for (int to : g[v]) {\n                if (!done[to]) continue;\n                if (depth[to] >= H) continue;\n                if (betterPar(to, bestPar)) bestPar = to;\n            }\n            if (bestPar != -1) {\n                parent[v] = bestPar;\n                depth[v] = depth[bestPar] + 1;\n            } else {\n                parent[v] = -1;\n                depth[v] = 0;\n            }\n            done[v] = 1;\n        }\n        return parent;\n    }\n\n    vector<int> bfsDist(int s) {\n        const int INF = 1e9;\n        vector<int> dist(N, INF);\n        queue<int> q;\n        dist[s] = 0;\n        q.push(s);\n        while (!q.empty()) {\n            int v = q.front(); q.pop();\n            for (int to : g[v]) {\n                if (dist[to] != INF) continue;\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n        return dist;\n    }\n\n    vector<int> buildBeautyOrder(double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = 1.0 * A[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildBeautyDegreeOrder(double wA, double wDeg, double noiseScale = 1e-4) {\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            key[v] = wA * A[v] - wDeg * deg[v] + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildProjectionOrder(double angle, double wA, double wP, double noiseScale = 1e-4) {\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> buildSeedDistOrder(int seed, double wD, double wA, double angle = 0.0,\n                                   double wP = 0.0, double noiseScale = 1e-4) {\n        auto dist = bfsDist(seed);\n        double cs = cos(angle), sn = sin(angle);\n        vector<double> key(N);\n        for (int v = 0; v < N; ++v) {\n            double proj = cs * X[v] + sn * Y[v];\n            key[v] = wD * dist[v] + wA * A[v] + wP * proj + noiseScale * rand01();\n        }\n        return buildFromKey(key);\n    }\n\n    vector<int> seedCandidates() {\n        vector<int> ord(N);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            long long da = 1LL * (X[a] - 500) * (X[a] - 500) + 1LL * (Y[a] - 500) * (Y[a] - 500);\n            long long db = 1LL * (X[b] - 500) * (X[b] - 500) + 1LL * (Y[b] - 500) * (Y[b] - 500);\n            double sa = 18.0 * A[a] - 2.5 * deg[a] + 0.002 * sqrt((double)da);\n            double sb = 18.0 * A[b] - 2.5 * deg[b] + 0.002 * sqrt((double)db);\n            if (sa != sb) return sa < sb;\n            return a < b;\n        });\n        int K = min(16, N);\n        ord.resize(K);\n        return ord;\n    }\n\n    // -------- candidate pipeline --------\n\n    void tryUpdate(const vector<int>& cand, vector<int>& bestParent, long long& bestScore) {\n        long long sc = calcScore(cand);\n        if (sc > bestScore) {\n            bestScore = sc;\n            bestParent = cand;\n        }\n    }\n\n    void processCandidate(vector<int> parent, bool randomizedFirst,\n                          vector<int>& bestParent, long long& bestScore) {\n        if (time_up()) return;\n\n        {\n            vector<int> depth = depthFromParent(parent);\n            depthLocalSearch(depth, randomizedFirst && remaining_ms() > 900);\n            parent = parentFromDepth(depth);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        if (remaining_ms() > 900) {\n            hillClimb(parent, randomizedFirst);\n            if (!time_up()) rerootOptimize(parent);\n            if (!time_up()) hillClimb(parent, false);\n            tryUpdate(parent, bestParent, bestScore);\n        } else if (remaining_ms() > 400) {\n            hillClimb(parent, false);\n            if (!time_up()) rerootOptimize(parent);\n            tryUpdate(parent, bestParent, bestScore);\n        } else {\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        {\n            vector<int> depth = depthFromParent(parent);\n            depthLocalSearch(depth, false);\n            parent = parentFromDepth(depth);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        if (remaining_ms() > 250) {\n            hillClimb(parent, false);\n            tryUpdate(parent, bestParent, bestScore);\n        }\n    }\n\n    void finalDeterministicPolish(vector<int>& bestParent, long long& bestScore) {\n        if (time_up()) return;\n        vector<int> p = bestParent;\n\n        {\n            vector<int> depth = depthFromParent(p);\n            depthLocalSearch(depth, false);\n            p = parentFromDepth(depth);\n            tryUpdate(p, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        if (remaining_ms() > 40) {\n            hillClimb(p, false);\n            tryUpdate(p, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        if (remaining_ms() > 20) {\n            rerootOptimize(p);\n            tryUpdate(p, bestParent, bestScore);\n        }\n        if (time_up()) return;\n\n        if (remaining_ms() > 10) {\n            hillClimb(p, false);\n            tryUpdate(p, bestParent, bestScore);\n        }\n    }\n\n    vector<int> solve() {\n        start_time = chrono::steady_clock::now();\n        deadline = start_time + chrono::milliseconds(1900);\n\n        vector<int> bestParent = buildAllRoots();\n        long long bestScore = calcScore(bestParent);\n\n        auto seeds = seedCandidates();\n\n        processCandidate(buildAllRoots(), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyOrder(), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyDegreeOrder(1.0, 1.5), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        processCandidate(buildBeautyDegreeOrder(1.6, 2.0), true, bestParent, bestScore);\n        if (time_up()) return bestParent;\n\n        const vector<double> fixedAngles = {\n            0.0,\n            acos(-1.0) / 4.0,\n            acos(-1.0) / 2.0,\n            3.0 * acos(-1.0) / 4.0\n        };\n        for (double ang : fixedAngles) {\n            if (time_up()) break;\n            processCandidate(buildProjectionOrder(ang, 1.3, 0.05), true, bestParent, bestScore);\n        }\n\n        for (int i = 0; i < (int)seeds.size() && i < 4 && !time_up(); ++i) {\n            int s = seeds[i];\n            double ang = 2.0 * acos(-1.0) * (i + 1) / 7.0;\n            processCandidate(buildSeedDistOrder(s, 10.0, 1.0, ang, 0.015), true, bestParent, bestScore);\n            if (time_up()) break;\n            processCandidate(buildSeedDistOrder(s, 14.0, 0.8, ang, 0.0), true, bestParent, bestScore);\n        }\n\n        int trial = 0;\n        while (remaining_ms() > 130 && !time_up()) {\n            vector<int> p;\n            int typ = trial % 5;\n\n            if (typ == 0) {\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wA = 0.8 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.08;\n                p = buildProjectionOrder(ang, wA, wP, 1e-3);\n            } else if (typ == 1) {\n                int s = seeds[uniform_int_distribution<int>(0, (int)seeds.size() - 1)(rng)];\n                double ang = rand01() * 2.0 * acos(-1.0);\n                double wD = 7.0 + 10.0 * rand01();\n                double wA = 0.6 + 1.8 * rand01();\n                double wP = (rand01() * 2.0 - 1.0) * 0.03;\n                p = buildSeedDistOrder(s, wD, wA, ang, wP);\n            } else if (typ == 2) {\n                double wA = 0.8 + 1.2 * rand01();\n                double wDeg = 0.5 + 2.5 * rand01();\n                p = buildBeautyDegreeOrder(wA, wDeg);\n            } else if (typ == 3) {\n                p = buildBeautyOrder(1e-3);\n            } else {\n                p = buildAllRoots();\n            }\n\n            processCandidate(p, remaining_ms() > 700, bestParent, bestScore);\n            ++trial;\n        }\n\n        finalDeterministicPolish(bestParent, bestScore);\n        return bestParent;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    cin >> solver.N >> solver.M >> solver.H;\n\n    solver.A.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) cin >> solver.A[i];\n\n    solver.edges.resize(solver.M);\n    solver.g.assign(solver.N, {});\n    solver.deg.assign(solver.N, 0);\n    solver.adjMat.assign(solver.N, {});\n\n    for (int i = 0; i < solver.M; ++i) {\n        int u, v;\n        cin >> u >> v;\n        solver.edges[i] = {u, v};\n        solver.g[u].push_back(v);\n        solver.g[v].push_back(u);\n        solver.deg[u]++;\n        solver.deg[v]++;\n        solver.adjMat[u].set(v);\n        solver.adjMat[v].set(u);\n    }\n\n    solver.X.resize(solver.N);\n    solver.Y.resize(solver.N);\n    for (int i = 0; i < solver.N; ++i) {\n        cin >> solver.X[i] >> solver.Y[i];\n    }\n\n    vector<int> ans = solver.solve();\n\n    for (int i = 0; i < solver.N; ++i) {\n        if (i) cout << ' ';\n        cout << ans[i];\n    }\n    cout << '\\n';\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 20;\nstatic constexpr int MAX_ONI = 40;\nstatic constexpr int SIDE = 80;\nstatic constexpr int MAXD = 20;\nstatic constexpr int MAXP = 32;\nstatic constexpr double TL = 1.92;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() : st(chrono::steady_clock::now()) {}\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n} timer_;\n\nmt19937_64 rng_(1);\n\ninline int sideL(int r) { return r; }\ninline int sideR(int r) { return 20 + r; }\ninline int sideU(int c) { return 40 + c; }\ninline int sideD(int c) { return 60 + c; }\n\ninline char sideDir(int s) {\n    if (s < 20) return 'L';\n    if (s < 40) return 'R';\n    if (s < 60) return 'U';\n    return 'D';\n}\ninline int sideIdx(int s) {\n    if (s < 20) return s;\n    if (s < 40) return s - 20;\n    if (s < 60) return s - 40;\n    return s - 60;\n}\ninline char revDir(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\nstruct Macro {\n    char d;\n    int p;\n    int k;\n};\n\ninline int macroSide(const Macro& a) {\n    if (a.d == 'L') return sideL(a.p);\n    if (a.d == 'R') return sideR(a.p);\n    if (a.d == 'U') return sideU(a.p);\n    return sideD(a.p);\n}\n\nstruct Board {\n    array<array<char, N>, N> g{};\n    int xcnt = 0;\n};\n\nstruct FinishData {\n    int m = 0;\n    bool safe = true;\n    array<pair<int,int>, MAX_ONI> pos{};\n    array<array<int, 4>, MAX_ONI> candList{};\n    array<int, MAX_ONI> candCnt{};\n    array<array<int, SIDE>, MAX_ONI> depthOf{};\n    array<int, MAX_ONI> minDepth{};\n    array<int, N> firstORow{}, lastORow{}, firstOCol{}, lastOCol{};\n};\n\nstruct State {\n    array<int, MAX_ONI> assign{};\n    array<array<unsigned char, MAXD + 1>, SIDE> cnt{};\n    array<int, SIDE> dep{};\n    array<unsigned long long, SIDE> mem{};\n    int S = 0;\n    int M = 0;\n    int cost() const { return S - M; }\n};\n\nstruct BeamNode {\n    Board b;\n    array<Macro, MAXP> pref{};\n    int plen = 0;\n    int prefixCost = 0;\n    int est = (int)1e9;\n    uint64_t h = 0;\n};\n\nstruct Endpoint {\n    Board b;\n    array<Macro, MAXP> pref{};\n    int plen = 0;\n    int prefixCost = 0;\n    int quickTotal = (int)1e9;\n    uint64_t h = 0;\n};\n\nuint64_t hashBoard(const Board& b) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            h ^= (uint64_t)(unsigned char)b.g[i][j];\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nvoid applyOne(Board& b, char d, int p) {\n    if (d == 'L') {\n        if (b.g[p][0] == 'x') b.xcnt--;\n        for (int j = 0; j + 1 < N; j++) b.g[p][j] = b.g[p][j + 1];\n        b.g[p][N - 1] = '.';\n    } else if (d == 'R') {\n        if (b.g[p][N - 1] == 'x') b.xcnt--;\n        for (int j = N - 1; j >= 1; j--) b.g[p][j] = b.g[p][j - 1];\n        b.g[p][0] = '.';\n    } else if (d == 'U') {\n        if (b.g[0][p] == 'x') b.xcnt--;\n        for (int i = 0; i + 1 < N; i++) b.g[i][p] = b.g[i + 1][p];\n        b.g[N - 1][p] = '.';\n    } else {\n        if (b.g[N - 1][p] == 'x') b.xcnt--;\n        for (int i = N - 1; i >= 1; i--) b.g[i][p] = b.g[i - 1][p];\n        b.g[0][p] = '.';\n    }\n}\n\nvoid applyMacro(Board& b, const Macro& a) {\n    for (int t = 0; t < a.k; t++) applyOne(b, a.d, a.p);\n}\n\nFinishData buildData(const Board& b) {\n    FinishData D;\n    for (int i = 0; i < N; i++) {\n        D.firstORow[i] = N;\n        D.lastORow[i] = -1;\n    }\n    for (int j = 0; j < N; j++) {\n        D.firstOCol[j] = N;\n        D.lastOCol[j] = -1;\n    }\n\n    D.m = 0;\n    D.safe = true;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] == 'o') {\n                D.firstORow[i] = min(D.firstORow[i], j);\n                D.lastORow[i] = max(D.lastORow[i], j);\n                D.firstOCol[j] = min(D.firstOCol[j], i);\n                D.lastOCol[j] = max(D.lastOCol[j], i);\n            }\n        }\n    }\n\n    for (int u = 0; u < MAX_ONI; u++) {\n        D.candCnt[u] = 0;\n        D.minDepth[u] = 1e9;\n        D.depthOf[u].fill(0);\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] != 'x') continue;\n            int u = D.m++;\n            D.pos[u] = {i, j};\n\n            auto addCand = [&](int s, int d) {\n                int c = D.candCnt[u];\n                D.candList[u][c] = s;\n                D.candCnt[u]++;\n                D.depthOf[u][s] = d;\n                D.minDepth[u] = min(D.minDepth[u], d);\n            };\n\n            if (j < D.firstORow[i]) addCand(sideL(i), j + 1);\n            if (j > D.lastORow[i]) addCand(sideR(i), N - j);\n            if (i < D.firstOCol[j]) addCand(sideU(j), i + 1);\n            if (i > D.lastOCol[j]) addCand(sideD(j), N - i);\n\n            if (D.candCnt[u] == 0) D.safe = false;\n        }\n    }\n    return D;\n}\n\nState emptyState() {\n    State st;\n    st.assign.fill(-1);\n    for (int s = 0; s < SIDE; s++) {\n        st.cnt[s].fill(0);\n        st.dep[s] = 0;\n        st.mem[s] = 0ULL;\n    }\n    st.S = 0;\n    st.M = 0;\n    return st;\n}\n\nState makeStateFromDep(const array<unsigned char, SIDE>& dep8) {\n    State st = emptyState();\n    for (int s = 0; s < SIDE; s++) {\n        st.dep[s] = dep8[s];\n        st.S += 2 * (int)dep8[s];\n        st.M = max(st.M, (int)dep8[s]);\n    }\n    return st;\n}\n\ninline int recomputeM(const State& st) {\n    int m = 0;\n    for (int s = 0; s < SIDE; s++) m = max(m, st.dep[s]);\n    return m;\n}\n\nvoid addAssign(State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    st.assign[u] = s;\n    st.mem[s] |= (1ULL << u);\n    st.cnt[s][d]++;\n    if (d > st.dep[s]) {\n        st.S += 2 * (d - st.dep[s]);\n        st.dep[s] = d;\n    }\n    if (st.dep[s] > st.M) st.M = st.dep[s];\n}\n\nvoid removeAssign(State& st, const FinishData& D, int u) {\n    int s = st.assign[u];\n    if (s < 0) return;\n    int d = D.depthOf[u][s];\n    st.assign[u] = -1;\n    st.mem[s] &= ~(1ULL << u);\n    st.cnt[s][d]--;\n    if (d == st.dep[s] && st.cnt[s][d] == 0) {\n        int nd = st.dep[s];\n        while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n        st.S += 2 * (nd - st.dep[s]);\n        st.dep[s] = nd;\n    }\n    st.M = recomputeM(st);\n}\n\ninline int secondDepthAfterRemoving(const State& st, int s, int remDepth) {\n    if (remDepth != st.dep[s]) return st.dep[s];\n    if (st.cnt[s][remDepth] >= 2) return st.dep[s];\n    int nd = st.dep[s] - 1;\n    while (nd > 0 && st.cnt[s][nd] == 0) --nd;\n    return nd;\n}\n\nint evalAdd(const State& st, const FinishData& D, int u, int s) {\n    int d = D.depthOf[u][s];\n    int nd = max(st.dep[s], d);\n    int newS = st.S + 2 * (nd - st.dep[s]);\n    int newM = max(st.M, nd);\n    return newS - newM;\n}\n\nint evalMove(const State& st, const FinishData& D, int u, int ns) {\n    int os = st.assign[u];\n    if (os == ns) return st.cost();\n\n    int od = D.depthOf[u][os];\n    int nd = D.depthOf[u][ns];\n    int depOldAfter = secondDepthAfterRemoving(st, os, od);\n    int depNewAfter = max(st.dep[ns], nd);\n\n    int newS = st.S + 2 * (depOldAfter - st.dep[os]) + 2 * (depNewAfter - st.dep[ns]);\n\n    int newM = 0;\n    for (int s = 0; s < SIDE; s++) {\n        int d = st.dep[s];\n        if (s == os) d = depOldAfter;\n        else if (s == ns) d = depNewAfter;\n        newM = max(newM, d);\n    }\n    return newS - newM;\n}\n\nvector<int> makeOrderDifficulty(const FinishData& D, bool randomized) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    vector<uint64_t> key(D.m);\n    for (int i = 0; i < D.m; i++) key[i] = rng_();\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (D.candCnt[a] != D.candCnt[b]) return D.candCnt[a] < D.candCnt[b];\n        if (D.minDepth[a] != D.minDepth[b]) return D.minDepth[a] > D.minDepth[b];\n        if (randomized) return key[a] < key[b];\n        return a < b;\n    });\n    return ord;\n}\n\nvector<int> makeOrderRandom(int m) {\n    vector<int> ord(m);\n    iota(ord.begin(), ord.end(), 0);\n    shuffle(ord.begin(), ord.end(), rng_);\n    return ord;\n}\n\nState buildGreedy(const FinishData& D, const vector<int>& ord, bool randomized) {\n    State st = emptyState();\n    for (int u : ord) {\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            opts[oc++] = {evalAdd(st, D, u, s), s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        int choose = opts[0].second;\n        if (randomized && oc > 1) {\n            int lim = 1;\n            while (lim < oc && opts[lim].first <= opts[0].first + 1) ++lim;\n            lim = min(lim, 3);\n            choose = opts[(int)(rng_() % lim)].second;\n        }\n        addAssign(st, D, u, choose);\n    }\n    return st;\n}\n\nState buildMinDepthState(const FinishData& D) {\n    State st = emptyState();\n    for (int u = 0; u < D.m; u++) {\n        int bestS = D.candList[u][0];\n        int bestD = D.depthOf[u][bestS];\n        for (int it = 1; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            int d = D.depthOf[u][s];\n            if (d < bestD || (d == bestD && s < bestS)) {\n                bestD = d;\n                bestS = s;\n            }\n        }\n        addAssign(st, D, u, bestS);\n    }\n    return st;\n}\n\nvoid local1(const FinishData& D, State& st, int rounds = 2) {\n    vector<int> ord(D.m);\n    iota(ord.begin(), ord.end(), 0);\n    for (int rep = 0; rep < rounds; rep++) {\n        bool improved = false;\n        for (int u : ord) {\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvector<int> membersOfMask(unsigned long long mask) {\n    vector<int> res;\n    while (mask) {\n        int b = __builtin_ctzll(mask);\n        res.push_back(b);\n        mask &= mask - 1;\n    }\n    return res;\n}\n\nbool exactReoptSubset(State& st, const FinishData& D, vector<int> subset, int forbidSide, double deadline) {\n    if (subset.empty()) return false;\n\n    State original = st;\n    for (int u : subset) removeAssign(st, D, u);\n\n    for (int u : subset) {\n        int ok = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != forbidSide) ok++;\n        }\n        if (ok == 0) {\n            st = original;\n            return false;\n        }\n    }\n\n    sort(subset.begin(), subset.end(), [&](int a, int b) {\n        int ca = 0, cb = 0;\n        for (int it = 0; it < D.candCnt[a]; it++) if (D.candList[a][it] != forbidSide) ca++;\n        for (int it = 0; it < D.candCnt[b]; it++) if (D.candList[b][it] != forbidSide) cb++;\n        if (ca != cb) return ca < cb;\n        return D.minDepth[a] > D.minDepth[b];\n    });\n\n    int bestCost = original.cost();\n    State bestState = original;\n    long long nodes = 0;\n    bool timeout = false;\n\n    function<void(int)> dfs = [&](int idx) {\n        if ((nodes++ & 1023LL) == 0 && timer_.elapsed() >= deadline) {\n            timeout = true;\n            return;\n        }\n        int curCost = st.cost();\n        if (curCost >= bestCost) return;\n        if (idx == (int)subset.size()) {\n            bestCost = curCost;\n            bestState = st;\n            return;\n        }\n\n        int u = subset[idx];\n        array<pair<int,int>, 4> opts;\n        int oc = 0;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            if (s == forbidSide) continue;\n            int c = evalAdd(st, D, u, s);\n            if (c < bestCost) opts[oc++] = {c, s};\n        }\n        sort(opts.begin(), opts.begin() + oc);\n\n        for (int i = 0; i < oc; i++) {\n            int s = opts[i].second;\n            int c = opts[i].first;\n            if (c >= bestCost) break;\n            addAssign(st, D, u, s);\n            dfs(idx + 1);\n            removeAssign(st, D, u);\n            if (timeout) return;\n        }\n    };\n\n    dfs(0);\n    st = bestState;\n    return st.cost() < original.cost();\n}\n\nbool exactCloseOneSide(State& st, const FinishData& D, int side, double deadline) {\n    int sz = __builtin_popcountll(st.mem[side]);\n    if (sz <= 1 || sz > 8) return false;\n    vector<int> subset = membersOfMask(st.mem[side]);\n    for (int u : subset) {\n        bool alt = false;\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            if (D.candList[u][it] != side) { alt = true; break; }\n        }\n        if (!alt) return false;\n    }\n    return exactReoptSubset(st, D, subset, side, deadline);\n}\n\nbool exactTwoSideReopt(State& st, const FinishData& D, int s1, int s2, double deadline) {\n    if (s1 == s2) return false;\n    unsigned long long mask = st.mem[s1] | st.mem[s2];\n    int sz = __builtin_popcountll(mask);\n    if (sz <= 1 || sz > 9) return false;\n    vector<int> subset = membersOfMask(mask);\n    return exactReoptSubset(st, D, subset, -1, deadline);\n}\n\nbool exactInterestingSubsetReopt(State& st, const FinishData& D, double deadline) {\n    vector<pair<pair<int,int>, int>> sides;\n    for (int s = 0; s < SIDE; s++) {\n        if (st.dep[s] == 0) continue;\n        int sz = __builtin_popcountll(st.mem[s]);\n        if (sz == 0) continue;\n        sides.push_back({{-st.dep[s], sz}, s});\n    }\n    if (sides.empty()) return false;\n    sort(sides.begin(), sides.end());\n\n    vector<int> pool;\n    bool used[MAX_ONI] = {};\n    int takeSides = min<int>(5, sides.size());\n    for (int i = 0; i < takeSides; i++) {\n        int s = sides[i].second;\n        auto mem = st.mem[s];\n        while (mem) {\n            int u = __builtin_ctzll(mem);\n            mem &= mem - 1;\n            if (!used[u]) {\n                used[u] = true;\n                pool.push_back(u);\n            }\n        }\n    }\n    if ((int)pool.size() <= 2) return false;\n\n    sort(pool.begin(), pool.end(), [&](int a, int b) {\n        if (D.candCnt[a] != D.candCnt[b]) return D.candCnt[a] < D.candCnt[b];\n        return D.minDepth[a] > D.minDepth[b];\n    });\n\n    if ((int)pool.size() > 8) pool.resize(8);\n    return exactReoptSubset(st, D, pool, -1, deadline);\n}\n\nvoid localImproveLight(const FinishData& D, State& st, double deadline) {\n    while (timer_.elapsed() < deadline) {\n        bool improved = false;\n        vector<int> ord(D.m);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng_);\n\n        for (int u : ord) {\n            if (timer_.elapsed() >= deadline) return;\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (!improved) break;\n    }\n}\n\nvoid localImproveStrong(const FinishData& D, State& st, double deadline) {\n    while (timer_.elapsed() < deadline) {\n        bool improved = false;\n\n        vector<int> ord(D.m);\n        iota(ord.begin(), ord.end(), 0);\n        shuffle(ord.begin(), ord.end(), rng_);\n\n        for (int u : ord) {\n            if (timer_.elapsed() >= deadline) return;\n            int curS = st.assign[u];\n            int bestS = curS;\n            int bestCost = st.cost();\n\n            for (int it = 0; it < D.candCnt[u]; it++) {\n                int s = D.candList[u][it];\n                if (s == curS) continue;\n                int c = evalMove(st, D, u, s);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestS = s;\n                }\n            }\n            if (bestS != curS) {\n                removeAssign(st, D, u);\n                addAssign(st, D, u, bestS);\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        vector<int> sides;\n        for (int s = 0; s < SIDE; s++) {\n            int sz = __builtin_popcountll(st.mem[s]);\n            if (sz >= 2 && sz <= 8) sides.push_back(s);\n        }\n        shuffle(sides.begin(), sides.end(), rng_);\n\n        for (int s : sides) {\n            if (timer_.elapsed() >= deadline) return;\n            if (exactCloseOneSide(st, D, s, deadline)) {\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid polishBestAdvanced(const FinishData& D, State& st, double deadline) {\n    while (timer_.elapsed() < deadline) {\n        bool improved = false;\n        int before = st.cost();\n\n        double rem = deadline - timer_.elapsed();\n        if (rem <= 0.001) break;\n\n        double end1 = min(deadline, timer_.elapsed() + min(0.003, rem * 0.35));\n        localImproveLight(D, st, end1);\n        if (st.cost() < before) {\n            improved = true;\n            continue;\n        }\n\n        vector<pair<pair<int,int>, int>> sides;\n        for (int s = 0; s < SIDE; s++) {\n            int sz = __builtin_popcountll(st.mem[s]);\n            if (sz > 0 && sz <= 8) sides.push_back({{-st.dep[s], sz}, s});\n        }\n        sort(sides.begin(), sides.end());\n\n        for (int i = 0; i < (int)sides.size() && i < 10 && timer_.elapsed() < deadline; i++) {\n            if (exactCloseOneSide(st, D, sides[i].second, deadline)) {\n                improved = true;\n                break;\n            }\n        }\n        if (improved) continue;\n\n        int pairTried = 0;\n        for (int i = 0; i < (int)sides.size() && i < 8 && timer_.elapsed() < deadline; i++) {\n            for (int j = i + 1; j < (int)sides.size() && j < 9 && timer_.elapsed() < deadline; j++) {\n                int s1 = sides[i].second, s2 = sides[j].second;\n                unsigned long long mask = st.mem[s1] | st.mem[s2];\n                int sz = __builtin_popcountll(mask);\n                if (sz >= 2 && sz <= 9) {\n                    if (exactTwoSideReopt(st, D, s1, s2, deadline)) {\n                        improved = true;\n                        break;\n                    }\n                    pairTried++;\n                    if (pairTried >= 10) break;\n                }\n            }\n            if (improved || pairTried >= 10) break;\n        }\n        if (improved) continue;\n\n        if (deadline - timer_.elapsed() > 0.003) {\n            for (int t = 0; t < 2 && timer_.elapsed() < deadline; t++) {\n                if (exactInterestingSubsetReopt(st, D, deadline)) {\n                    improved = true;\n                    break;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nState quickSolve(const FinishData& D) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    State best = buildGreedy(D, makeOrderDifficulty(D, false), false);\n    local1(D, best, 2);\n\n    State alt = buildMinDepthState(D);\n    local1(D, alt, 2);\n    if (alt.cost() < best.cost()) best = alt;\n\n    return best;\n}\n\nState strongSolve(const FinishData& D, double deadline) {\n    if (!D.safe) return emptyState();\n    if (D.m == 0) return emptyState();\n\n    double start = timer_.elapsed();\n    double total = deadline - start;\n    State best = quickSolve(D);\n    if (total <= 0.003) return best;\n\n    {\n        double rem = deadline - timer_.elapsed();\n        double slice = min(rem, (rem >= 0.03 ? 0.014 : 0.006));\n        if (slice > 0.0) {\n            double endt = timer_.elapsed() + slice;\n            if (slice >= 0.010) localImproveStrong(D, best, endt);\n            else localImproveLight(D, best, endt);\n        }\n    }\n\n    double reserve = min(0.010, max(0.004, total * 0.22));\n    int iter = 0;\n    while (timer_.elapsed() + reserve < deadline) {\n        double rem = deadline - timer_.elapsed() - reserve;\n        if (rem <= 0.001) break;\n\n        State st;\n        if (iter % 3 == 0) st = buildGreedy(D, makeOrderDifficulty(D, true), true);\n        else if (iter % 3 == 1) st = buildGreedy(D, makeOrderRandom(D.m), true);\n        else st = buildMinDepthState(D);\n\n        double slice = min(rem, rem >= 0.03 ? 0.012 : (rem >= 0.012 ? 0.007 : rem));\n        double endt = timer_.elapsed() + slice;\n\n        if (slice >= 0.010) localImproveStrong(D, st, endt);\n        else localImproveLight(D, st, endt);\n\n        if (st.cost() < best.cost()) best = st;\n        iter++;\n    }\n\n    if (timer_.elapsed() < deadline) {\n        polishBestAdvanced(D, best, deadline);\n    }\n    return best;\n}\n\nbool exactSolveSmall(const FinishData& D, const State& incumbent, double deadline, State& out) {\n    if (!D.safe) return false;\n    if (D.m == 0) {\n        out = emptyState();\n        return true;\n    }\n    if (D.m > 11) return false;\n    if (timer_.elapsed() >= deadline) return false;\n\n    int full = 1 << D.m;\n    int fullMask = full - 1;\n    int SZ = full * 2;\n    const int INF = 1e9;\n\n    array<char, SIDE> active{};\n    active.fill(0);\n    bool seenMax[21] = {};\n\n    for (int u = 0; u < D.m; u++) {\n        for (int it = 0; it < D.candCnt[u]; it++) {\n            int s = D.candList[u][it];\n            int d = D.depthOf[u][s];\n            active[s] = 1;\n            seenMax[d] = true;\n        }\n    }\n\n    vector<int> sides;\n    for (int s = 0; s < SIDE; s++) if (active[s]) sides.push_back(s);\n    if (sides.empty()) return false;\n    int K = (int)sides.size();\n\n    vector<int> possibleMax;\n    for (int d = 1; d <= 20; d++) if (seenMax[d]) possibleMax.push_back(d);\n\n    vector<vector<int>> optDepth(K), optCover(K);\n    for (int i = 0; i < K; i++) {\n        int s = sides[i];\n        vector<int> deps;\n        for (int u = 0; u < D.m; u++) {\n            int dd = D.depthOf[u][s];\n            if (dd > 0) deps.push_back(dd);\n        }\n        sort(deps.begin(), deps.end());\n        deps.erase(unique(deps.begin(), deps.end()), deps.end());\n\n        int prevMask = -1;\n        for (int d : deps) {\n            int mask = 0;\n            for (int u = 0; u < D.m; u++) {\n                int dd = D.depthOf[u][s];\n                if (dd > 0 && dd <= d) mask |= (1 << u);\n            }\n            if (mask == prevMask) continue;\n            prevMask = mask;\n            optDepth[i].push_back(d);\n            optCover[i].push_back(mask);\n        }\n    }\n\n    int bestCost = incumbent.cost();\n    int bestDmax = -1;\n\n    vector<int> dp(SZ), ndp(SZ);\n\n    for (int Dmax : possibleMax) {\n        if (timer_.elapsed() >= deadline) break;\n\n        bool possible = false;\n        for (int i = 0; i < K; i++) {\n            for (int d : optDepth[i]) if (d == Dmax) { possible = true; break; }\n            if (possible) break;\n        }\n        if (!possible) continue;\n\n        int lim2 = bestCost + Dmax;\n\n        fill(dp.begin(), dp.end(), INF);\n        dp[0] = 0;\n\n        for (int i = 0; i < K; i++) {\n            fill(ndp.begin(), ndp.end(), INF);\n\n            for (int st = 0; st < SZ; st++) {\n                int cur = dp[st];\n                if (cur < ndp[st]) ndp[st] = cur;\n            }\n\n            int L = (int)optDepth[i].size();\n            for (int oi = 0; oi < L; oi++) {\n                int d = optDepth[i][oi];\n                if (d > Dmax) break;\n                int add = 2 * d;\n                int cov = optCover[i][oi];\n                int eq = (d == Dmax);\n\n                for (int st = 0; st < SZ; st++) {\n                    int cur = dp[st];\n                    if (cur >= lim2) continue;\n                    int nc = cur + add;\n                    if (nc >= lim2) continue;\n                    int mask = st & fullMask;\n                    int flag = (st >= full);\n                    int nst = (flag | eq) * full + (mask | cov);\n                    if (nc < ndp[nst]) ndp[nst] = nc;\n                }\n            }\n            dp.swap(ndp);\n        }\n\n        int total2 = dp[full + fullMask];\n        if (total2 < lim2) {\n            int cost = total2 - Dmax;\n            if (cost < bestCost) {\n                bestCost = cost;\n                bestDmax = Dmax;\n            }\n        }\n    }\n\n    if (bestDmax < 0) return false;\n\n    vector<int> dp2(SZ, INF), ndp2(SZ, INF);\n    vector<int> parentState((K + 1) * SZ, -1);\n    vector<unsigned char> parentDepth((K + 1) * SZ, 0);\n\n    auto IDX = [&](int step, int st) { return step * SZ + st; };\n\n    int lim2 = bestCost + bestDmax;\n    dp2[0] = 0;\n\n    for (int i = 0; i < K; i++) {\n        fill(ndp2.begin(), ndp2.end(), INF);\n\n        for (int st = 0; st < SZ; st++) {\n            int cur = dp2[st];\n            if (cur < ndp2[st]) {\n                ndp2[st] = cur;\n                parentState[IDX(i + 1, st)] = st;\n                parentDepth[IDX(i + 1, st)] = 0;\n            }\n        }\n\n        int L = (int)optDepth[i].size();\n        for (int oi = 0; oi < L; oi++) {\n            int d = optDepth[i][oi];\n            if (d > bestDmax) break;\n            int add = 2 * d;\n            int cov = optCover[i][oi];\n            int eq = (d == bestDmax);\n\n            for (int st = 0; st < SZ; st++) {\n                int cur = dp2[st];\n                if (cur >= lim2) continue;\n                int nc = cur + add;\n                if (nc >= lim2) continue;\n                int mask = st & fullMask;\n                int flag = (st >= full);\n                int nst = (flag | eq) * full + (mask | cov);\n                if (nc < ndp2[nst]) {\n                    ndp2[nst] = nc;\n                    parentState[IDX(i + 1, nst)] = st;\n                    parentDepth[IDX(i + 1, nst)] = (unsigned char)d;\n                }\n            }\n        }\n        dp2.swap(ndp2);\n    }\n\n    int target = full + fullMask;\n    if (dp2[target] - bestDmax != bestCost) return false;\n\n    array<unsigned char, SIDE> dep8{};\n    dep8.fill(0);\n\n    int cur = target;\n    for (int i = K; i >= 1; i--) {\n        dep8[sides[i - 1]] = parentDepth[IDX(i, cur)];\n        cur = parentState[IDX(i, cur)];\n        if (cur < 0) return false;\n    }\n\n    out = makeStateFromDep(dep8);\n    return true;\n}\n\nvoid emitSide(vector<pair<char,int>>& ops, int side, int depth, bool restore) {\n    char d = sideDir(side);\n    char rd = revDir(d);\n    int p = sideIdx(side);\n    for (int t = 0; t < depth; t++) ops.push_back({d, p});\n    if (restore) {\n        for (int t = 0; t < depth; t++) ops.push_back({rd, p});\n    }\n}\n\nvector<pair<char,int>> buildFinishOps(const State& st) {\n    vector<int> used;\n    for (int s = 0; s < SIDE; s++) if (st.dep[s] > 0) used.push_back(s);\n    vector<pair<char,int>> ops;\n    if (used.empty()) return ops;\n\n    int finalSide = used[0];\n    for (int s : used) {\n        if (st.dep[s] > st.dep[finalSide]) finalSide = s;\n    }\n\n    sort(used.begin(), used.end(), [&](int a, int b) {\n        if (st.dep[a] != st.dep[b]) return st.dep[a] < st.dep[b];\n        return a < b;\n    });\n\n    for (int s : used) {\n        if (s == finalSide) continue;\n        emitSide(ops, s, st.dep[s], true);\n    }\n    emitSide(ops, finalSide, st.dep[finalSide], false);\n    return ops;\n}\n\nvector<pair<char,int>> buildPlan(const array<Macro, MAXP>& pref, int plen, const State& st) {\n    vector<pair<char,int>> ops;\n    for (int i = 0; i < plen; i++) {\n        for (int t = 0; t < pref[i].k; t++) ops.push_back({pref[i].d, pref[i].p});\n    }\n    auto fin = buildFinishOps(st);\n    ops.insert(ops.end(), fin.begin(), fin.end());\n    return ops;\n}\n\npair<int,int> simulate(const Board& init, const vector<pair<char,int>>& ops) {\n    Board b = init;\n    int removedO = 0;\n    for (auto [d, p] : ops) {\n        if (d == 'L') {\n            if (b.g[p][0] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'R') {\n            if (b.g[p][N - 1] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else if (d == 'U') {\n            if (b.g[0][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        } else {\n            if (b.g[N - 1][p] == 'o') removedO++;\n            applyOne(b, d, p);\n        }\n    }\n    return {b.xcnt, removedO};\n}\n\nstruct ActionCand {\n    Macro a;\n    int s0;\n    int s1;\n};\n\nvector<Macro> enumerateActions(const Board& b, const FinishData& D, int cap = 80) {\n    array<int, N> rowX{}, colX{};\n    for (int i = 0; i < N; i++) rowX[i] = 0;\n    for (int j = 0; j < N; j++) colX[j] = 0;\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (b.g[i][j] == 'x') {\n                rowX[i]++;\n                colX[j]++;\n            }\n        }\n    }\n\n    int idx[SIDE][MAXD + 1];\n    for (int s = 0; s < SIDE; s++) for (int d = 0; d <= MAXD; d++) idx[s][d] = -1;\n\n    vector<ActionCand> all;\n    all.reserve(400);\n\n    auto pushAct = [&](Macro a, int s0, int s1) {\n        if (a.k <= 0 || a.k > 20) return;\n        int s = macroSide(a);\n        int &id = idx[s][a.k];\n        if (id == -1) {\n            id = (int)all.size();\n            all.push_back({a, s0, s1});\n        } else {\n            all[id].s0 = max(all[id].s0, s0);\n            all[id].s1 = max(all[id].s1, s1);\n        }\n    };\n\n    auto addSetup = [&](char d, int p, int lim, int mass, bool hasXSafe) {\n        if (lim > 1) pushAct({d, p, lim}, (hasXSafe ? 7 : 22) * mass - 5 * lim, 28 * mass - 3 * lim);\n        if (lim >= 2) pushAct({d, p, 2}, (hasXSafe ? 10 : 16) * mass - 7, 22 * mass - 6);\n        if (lim >= 3) pushAct({d, p, 3}, (hasXSafe ? 8 : 12) * mass - 10, 18 * mass - 8);\n        if (lim >= 4) pushAct({d, p, 4}, (hasXSafe ? 6 : 10) * mass - 12, 16 * mass - 10);\n    };\n\n    for (int r = 0; r < N; r++) {\n        int limL = D.firstORow[r];\n        int removed = 0;\n        bool hasXSafe = false;\n        for (int j = 0; j < limL; j++) {\n            if (b.g[r][j] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'L', r, j + 1}, 260 * removed - 10 * (j + 1), 190 * removed - 8 * (j + 1));\n            }\n        }\n        if (rowX[r] > 0) addSetup('L', r, limL, rowX[r], hasXSafe);\n\n        int limR = (D.lastORow[r] == -1 ? N : N - 1 - D.lastORow[r]);\n        removed = 0;\n        hasXSafe = false;\n        for (int j = N - 1; j >= N - limR; j--) {\n            if (b.g[r][j] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'R', r, N - j}, 260 * removed - 10 * (N - j), 190 * removed - 8 * (N - j));\n            }\n        }\n        if (rowX[r] > 0) addSetup('R', r, limR, rowX[r], hasXSafe);\n    }\n\n    for (int c = 0; c < N; c++) {\n        int limU = D.firstOCol[c];\n        int removed = 0;\n        bool hasXSafe = false;\n        for (int i = 0; i < limU; i++) {\n            if (b.g[i][c] == 'x') {\n                removed++;\n                hasXSafe = true;\n                pushAct({'U', c, i + 1}, 260 * removed - 10 * (i + 1), 190 * removed - 8 * (i + 1));\n            }\n        }\n        if (colX[c] > 0) addSetup('U', c, limU, colX[c], hasXSafe);\n\n        int limD = (D.lastOCol[c] == -1 ? N : N - 1 - D.lastOCol[c]);\n        removed = 0;\n        bool hasXSafe2 = false;\n        for (int i = N - 1; i >= N - limD; i--) {\n            if (b.g[i][c] == 'x') {\n                removed++;\n                hasXSafe2 = true;\n                pushAct({'D', c, N - i}, 260 * removed - 10 * (N - i), 190 * removed - 8 * (N - i));\n            }\n        }\n        if (colX[c] > 0) addSetup('D', c, limD, colX[c], hasXSafe2);\n    }\n\n    for (int r = 0; r < N; r++) {\n        if (rowX[r] > 0) {\n            if (b.g[r][0] != 'o') pushAct({'L', r, 1}, 14 * rowX[r] - 4, 20 * rowX[r] - 3);\n            if (b.g[r][N - 1] != 'o') pushAct({'R', r, 1}, 14 * rowX[r] - 4, 20 * rowX[r] - 3);\n        }\n    }\n    for (int c = 0; c < N; c++) {\n        if (colX[c] > 0) {\n            if (b.g[0][c] != 'o') pushAct({'U', c, 1}, 14 * colX[c] - 4, 20 * colX[c] - 3);\n            if (b.g[N - 1][c] != 'o') pushAct({'D', c, 1}, 14 * colX[c] - 4, 20 * colX[c] - 3);\n        }\n    }\n\n    auto cmp0 = [&](int ia, int ib) {\n        const auto &A = all[ia], &B = all[ib];\n        if (A.s0 != B.s0) return A.s0 > B.s0;\n        if (A.a.k != B.a.k) return A.a.k < B.a.k;\n        if (A.a.d != B.a.d) return A.a.d < B.a.d;\n        return A.a.p < B.a.p;\n    };\n    auto cmp1 = [&](int ia, int ib) {\n        const auto &A = all[ia], &B = all[ib];\n        if (A.s1 != B.s1) return A.s1 > B.s1;\n        if (A.a.k != B.a.k) return A.a.k < B.a.k;\n        if (A.a.d != B.a.d) return A.a.d < B.a.d;\n        return A.a.p < B.a.p;\n    };\n\n    vector<int> ord0(all.size()), ord1(all.size());\n    iota(ord0.begin(), ord0.end(), 0);\n    iota(ord1.begin(), ord1.end(), 0);\n    sort(ord0.begin(), ord0.end(), cmp0);\n    sort(ord1.begin(), ord1.end(), cmp1);\n\n    vector<char> used(all.size(), 0);\n    vector<Macro> res;\n    res.reserve(cap);\n\n    int take0 = cap * 2 / 3;\n    int take1 = cap / 2;\n\n    for (int i = 0; i < (int)ord0.size() && (int)res.size() < take0; i++) {\n        int id = ord0[i];\n        if (!used[id]) {\n            used[id] = 1;\n            res.push_back(all[id].a);\n        }\n    }\n    for (int i = 0; i < (int)ord1.size() && (int)res.size() < take0 + take1; i++) {\n        int id = ord1[i];\n        if (!used[id]) {\n            used[id] = 1;\n            res.push_back(all[id].a);\n        }\n    }\n    for (int i = 0; i < (int)ord0.size() && (int)res.size() < cap; i++) {\n        int id = ord0[i];\n        if (!used[id]) {\n            used[id] = 1;\n            res.push_back(all[id].a);\n        }\n    }\n    for (int i = 0; i < (int)ord1.size() && (int)res.size() < cap; i++) {\n        int id = ord1[i];\n        if (!used[id]) {\n            used[id] = 1;\n            res.push_back(all[id].a);\n        }\n    }\n\n    return res;\n}\n\nvoid addEndpoint(vector<Endpoint>& eps, const Endpoint& e, int keep = 60) {\n    for (auto& x : eps) {\n        if (x.h == e.h) {\n            if (e.quickTotal < x.quickTotal ||\n                (e.quickTotal == x.quickTotal && e.prefixCost < x.prefixCost) ||\n                (e.quickTotal == x.quickTotal && e.prefixCost == x.prefixCost && e.b.xcnt < x.b.xcnt)) {\n                x = e;\n            }\n            return;\n        }\n    }\n    eps.push_back(e);\n\n    // Keep a bit more diversity: quickTotal, then xcnt, then prefixCost.\n    sort(eps.begin(), eps.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n        return a.prefixCost < b.prefixCost;\n    });\n    if ((int)eps.size() > keep) eps.resize(keep);\n}\n\nEndpoint greedyDescendEndpoint(Endpoint ep, int maxSteps, double deadline) {\n    for (int step = 0; step < maxSteps && timer_.elapsed() < deadline; step++) {\n        FinishData D = buildData(ep.b);\n        if (!D.safe) break;\n        State curSt = quickSolve(D);\n        int curTotal = ep.prefixCost + curSt.cost();\n\n        auto acts = enumerateActions(ep.b, D, 40);\n        int bestTotal = curTotal;\n        int bestX = ep.b.xcnt;\n        bool found = false;\n        Macro bestA{};\n        Board bestB;\n\n        for (const auto& a : acts) {\n            if (timer_.elapsed() >= deadline) break;\n            if (ep.plen >= MAXP) break;\n            if (ep.prefixCost + a.k >= 4 * N * N) continue;\n\n            Board nb = ep.b;\n            applyMacro(nb, a);\n            FinishData ND = buildData(nb);\n            if (!ND.safe) continue;\n\n            State qst = quickSolve(ND);\n            int total = ep.prefixCost + a.k + qst.cost();\n\n            if (total < bestTotal || (total == bestTotal && nb.xcnt < bestX)) {\n                bestTotal = total;\n                bestX = nb.xcnt;\n                bestA = a;\n                bestB = nb;\n                found = true;\n            }\n        }\n\n        if (!found) break;\n        ep.b = bestB;\n        ep.pref[ep.plen++] = bestA;\n        ep.prefixCost += bestA.k;\n        ep.quickTotal = bestTotal;\n        ep.h = hashBoard(ep.b);\n    }\n    return ep;\n}\n\nvector<Endpoint> perturbAndDescendEndpoints(const Endpoint& base, int branchCount, int descendSteps, double deadline) {\n    vector<Endpoint> out;\n    if (timer_.elapsed() >= deadline || base.plen >= MAXP) return out;\n\n    FinishData D = buildData(base.b);\n    if (!D.safe) return out;\n\n    State curSt = quickSolve(D);\n    int curTotal = base.prefixCost + curSt.cost();\n\n    auto acts = enumerateActions(base.b, D, 28);\n\n    struct Cand {\n        Endpoint ep;\n        int total;\n        int x;\n    };\n    vector<Cand> cands;\n    cands.reserve(28);\n\n    for (const auto& a : acts) {\n        if (timer_.elapsed() >= deadline) break;\n        if (base.prefixCost + a.k >= 4 * N * N) continue;\n        if (base.plen >= MAXP) break;\n\n        Board nb = base.b;\n        applyMacro(nb, a);\n        FinishData ND = buildData(nb);\n        if (!ND.safe) continue;\n\n        State qst = quickSolve(ND);\n        int total = base.prefixCost + a.k + qst.cost();\n        int allowance = (a.k <= 2 ? 6 : 4);\n\n        if (total <= curTotal + allowance || nb.xcnt < base.b.xcnt) {\n            Endpoint ep = base;\n            ep.b = nb;\n            ep.pref[ep.plen++] = a;\n            ep.prefixCost += a.k;\n            ep.quickTotal = total;\n            ep.h = hashBoard(nb);\n            cands.push_back({ep, total, nb.xcnt});\n        }\n    }\n    if (cands.empty()) return out;\n\n    vector<int> ordA(cands.size()), ordB(cands.size());\n    iota(ordA.begin(), ordA.end(), 0);\n    iota(ordB.begin(), ordB.end(), 0);\n\n    sort(ordA.begin(), ordA.end(), [&](int a, int b) {\n        if (cands[a].total != cands[b].total) return cands[a].total < cands[b].total;\n        if (cands[a].x != cands[b].x) return cands[a].x < cands[b].x;\n        return cands[a].ep.prefixCost < cands[b].ep.prefixCost;\n    });\n    sort(ordB.begin(), ordB.end(), [&](int a, int b) {\n        if (cands[a].x != cands[b].x) return cands[a].x < cands[b].x;\n        if (cands[a].total != cands[b].total) return cands[a].total < cands[b].total;\n        return cands[a].ep.prefixCost < cands[b].ep.prefixCost;\n    });\n\n    vector<char> used(cands.size(), 0);\n    vector<int> pick;\n    pick.reserve(branchCount);\n\n    auto take = [&](const vector<int>& ord, int lim) {\n        for (int id : ord) {\n            if ((int)pick.size() >= lim) break;\n            if (!used[id]) {\n                used[id] = 1;\n                pick.push_back(id);\n            }\n        }\n    };\n\n    take(ordA, max(1, branchCount / 2));\n    take(ordB, branchCount);\n    take(ordA, branchCount);\n\n    for (int id : pick) {\n        if (timer_.elapsed() >= deadline) break;\n        Endpoint ep = greedyDescendEndpoint(cands[id].ep, descendSteps, deadline);\n        out.push_back(ep);\n    }\n    return out;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int n_in;\n    cin >> n_in;\n\n    Board init;\n    init.xcnt = 0;\n    for (int i = 0; i < N; i++) {\n        string s;\n        cin >> s;\n        for (int j = 0; j < N; j++) {\n            init.g[i][j] = s[j];\n            if (s[j] == 'x') init.xcnt++;\n        }\n    }\n\n    uint64_t seed = hashBoard(init) ^ 0x9e3779b97f4a7c15ULL;\n    rng_.seed(seed);\n\n    vector<pair<char,int>> bestOps;\n    int bestLen = (int)1e9;\n\n    FinishData D0 = buildData(init);\n    if (D0.safe) {\n        State q0 = quickSolve(D0);\n        auto ops = buildFinishOps(q0);\n        auto [rx, ry] = simulate(init, ops);\n        if ((int)ops.size() <= 4 * N * N && rx == 0 && ry == 0) {\n            bestOps = ops;\n            bestLen = (int)ops.size();\n        }\n\n        double baseBudget = min(0.10, TL * 0.06);\n        State s0 = strongSolve(D0, min(TL - 0.05, timer_.elapsed() + baseBudget));\n        auto ops2 = buildFinishOps(s0);\n        auto [rx2, ry2] = simulate(init, ops2);\n        if ((int)ops2.size() <= 4 * N * N && rx2 == 0 && ry2 == 0) {\n            if ((int)ops2.size() < bestLen) {\n                bestOps = ops2;\n                bestLen = (int)ops2.size();\n            }\n        }\n    }\n\n    vector<Endpoint> endpoints;\n    {\n        Endpoint ep;\n        ep.b = init;\n        ep.plen = 0;\n        ep.prefixCost = 0;\n        ep.quickTotal = bestLen;\n        ep.h = hashBoard(init);\n        addEndpoint(endpoints, ep, 60);\n    }\n\n    vector<BeamNode> beam;\n    {\n        BeamNode st;\n        st.b = init;\n        st.plen = 0;\n        st.prefixCost = 0;\n        st.est = bestLen;\n        st.h = hashBoard(init);\n        beam.push_back(st);\n    }\n\n    unordered_map<uint64_t, int> bestPrefixCost;\n    bestPrefixCost.reserve(1 << 15);\n    bestPrefixCost[hashBoard(init)] = 0;\n\n    const int BEAM_WIDTH = 24;\n    const int BEAM_DEPTH = 18;\n    double beamEnd = 1.38;\n\n    for (int dep = 0; dep < BEAM_DEPTH && timer_.elapsed() < beamEnd && !beam.empty(); dep++) {\n        vector<BeamNode> cand;\n        cand.reserve(BEAM_WIDTH * 110);\n\n        int actionCap = (dep < 3 ? 104 : (dep < 8 ? 90 : 76));\n\n        for (const auto& node : beam) {\n            if (timer_.elapsed() >= beamEnd) break;\n            FinishData D = buildData(node.b);\n            if (!D.safe) continue;\n\n            auto acts = enumerateActions(node.b, D, actionCap);\n\n            for (const auto& a : acts) {\n                if (timer_.elapsed() >= beamEnd) break;\n                if (node.plen >= MAXP) continue;\n\n                BeamNode child = node;\n                applyMacro(child.b, a);\n                child.pref[child.plen++] = a;\n                child.prefixCost += a.k;\n                if (child.prefixCost >= 4 * N * N) continue;\n\n                child.h = hashBoard(child.b);\n                auto it = bestPrefixCost.find(child.h);\n                if (it != bestPrefixCost.end() && it->second <= child.prefixCost) continue;\n\n                FinishData ND = buildData(child.b);\n                if (!ND.safe) continue;\n\n                State qst = quickSolve(ND);\n                child.est = child.prefixCost + qst.cost();\n\n                auto it2 = bestPrefixCost.find(child.h);\n                if (it2 == bestPrefixCost.end() || child.prefixCost < it2->second) {\n                    bestPrefixCost[child.h] = child.prefixCost;\n                }\n\n                if (child.est < bestLen) {\n                    auto ops3 = buildPlan(child.pref, child.plen, qst);\n                    auto [rx3, ry3] = simulate(init, ops3);\n                    if ((int)ops3.size() <= 4 * N * N && rx3 == 0 && ry3 == 0) {\n                        bestLen = (int)ops3.size();\n                        bestOps = std::move(ops3);\n                    }\n                }\n\n                Endpoint ep;\n                ep.b = child.b;\n                ep.pref = child.pref;\n                ep.plen = child.plen;\n                ep.prefixCost = child.prefixCost;\n                ep.quickTotal = child.est;\n                ep.h = child.h;\n                addEndpoint(endpoints, ep, 60);\n\n                cand.push_back(std::move(child));\n            }\n        }\n\n        vector<BeamNode> nxt;\n        nxt.reserve(BEAM_WIDTH);\n        unordered_set<uint64_t> used;\n        used.reserve(BEAM_WIDTH * 8);\n\n        auto add_from_sorted = [&](auto cmp, int limit) {\n            sort(cand.begin(), cand.end(), cmp);\n            for (auto& x : cand) {\n                if ((int)nxt.size() >= limit) break;\n                if (used.insert(x.h).second) nxt.push_back(x);\n            }\n        };\n\n        add_from_sorted([&](const BeamNode& a, const BeamNode& b) {\n            if (a.est != b.est) return a.est < b.est;\n            if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n            if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n            return a.plen < b.plen;\n        }, 14);\n\n        add_from_sorted([&](const BeamNode& a, const BeamNode& b) {\n            if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n            if (a.est != b.est) return a.est < b.est;\n            if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n            return a.plen < b.plen;\n        }, 20);\n\n        add_from_sorted([&](const BeamNode& a, const BeamNode& b) {\n            if (a.prefixCost != b.prefixCost) return a.prefixCost < b.prefixCost;\n            if (a.est != b.est) return a.est < b.est;\n            return a.b.xcnt < b.b.xcnt;\n        }, BEAM_WIDTH);\n\n        if ((int)nxt.size() < BEAM_WIDTH && !cand.empty()) {\n            shuffle(cand.begin(), cand.end(), rng_);\n            for (auto& x : cand) {\n                if ((int)nxt.size() >= BEAM_WIDTH) break;\n                if (used.insert(x.h).second) nxt.push_back(x);\n            }\n        }\n\n        beam.swap(nxt);\n    }\n\n    sort(endpoints.begin(), endpoints.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n        return a.prefixCost < b.prefixCost;\n    });\n\n    int improveCnt = min<int>(12, endpoints.size());\n    for (int i = 0; i < improveCnt && timer_.elapsed() < 1.58; i++) {\n        Endpoint imp = greedyDescendEndpoint(endpoints[i], 8, 1.58);\n        addEndpoint(endpoints, imp, 60);\n    }\n\n    sort(endpoints.begin(), endpoints.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n        return a.prefixCost < b.prefixCost;\n    });\n\n    int perturbCnt = min<int>(10, endpoints.size());\n    for (int i = 0; i < perturbCnt && timer_.elapsed() < 1.72; i++) {\n        int bc = (i < 2 ? 5 : (i < 5 ? 4 : 3));\n        int ds = (i < 2 ? 6 : 5);\n        auto more = perturbAndDescendEndpoints(endpoints[i], bc, ds, 1.72);\n        for (auto& ep : more) addEndpoint(endpoints, ep, 60);\n    }\n\n    sort(endpoints.begin(), endpoints.end(), [&](const Endpoint& a, const Endpoint& b) {\n        if (a.quickTotal != b.quickTotal) return a.quickTotal < b.quickTotal;\n        if (a.b.xcnt != b.b.xcnt) return a.b.xcnt < b.b.xcnt;\n        return a.prefixCost < b.prefixCost;\n    });\n\n    for (int i = 0; i < (int)endpoints.size(); i++) {\n        if (timer_.elapsed() >= TL - 0.03) break;\n        if (i >= 28 && endpoints[i].quickTotal >= bestLen + 6) continue;\n\n        double remain = TL - 0.02 - timer_.elapsed();\n        int left = max(1, (int)endpoints.size() - i);\n\n        double factor = 1.0;\n        if (i < 3) factor = 2.2;\n        else if (i < 8) factor = 1.55;\n        else if (i < 18) factor = 1.18;\n        else factor = 0.82;\n\n        double budget = min(0.18, max(0.021, remain / left * factor));\n        double endt = min(TL - 0.02, timer_.elapsed() + budget);\n\n        FinishData D = buildData(endpoints[i].b);\n        if (!D.safe) continue;\n\n        State st;\n        double remNow = endt - timer_.elapsed();\n        bool tryExact =\n            (i < 4 && D.m <= 11 && remNow > 0.017) ||\n            (i < 12 && D.m <= 10 && remNow > 0.012);\n\n        if (tryExact) {\n            double tail = (D.m <= 10 ? 0.007 : 0.009);\n            double mid = max(timer_.elapsed(), endt - tail);\n            st = strongSolve(D, mid);\n            if (timer_.elapsed() < endt) {\n                State ex;\n                if (exactSolveSmall(D, st, endt, ex) && ex.cost() < st.cost()) st = ex;\n            }\n        } else {\n            st = strongSolve(D, endt);\n        }\n\n        int total = endpoints[i].prefixCost + st.cost();\n        if (total >= bestLen) continue;\n\n        auto ops4 = buildPlan(endpoints[i].pref, endpoints[i].plen, st);\n        auto [rx4, ry4] = simulate(init, ops4);\n        if ((int)ops4.size() <= 4 * N * N && rx4 == 0 && ry4 == 0) {\n            if ((int)ops4.size() < bestLen) {\n                bestLen = (int)ops4.size();\n                bestOps = std::move(ops4);\n            }\n        }\n    }\n\n    if (bestOps.empty()) {\n        FinishData D = buildData(init);\n        State st = quickSolve(D);\n        bestOps = buildFinishOps(st);\n    } else {\n        auto [rx, ry] = simulate(init, bestOps);\n        if (!((int)bestOps.size() <= 4 * N * N && rx == 0 && ry == 0)) {\n            FinishData D = buildData(init);\n            State st = quickSolve(D);\n            auto ops = buildFinishOps(st);\n            auto [rx2, ry2] = simulate(init, ops);\n            if ((int)ops.size() <= 4 * N * N && rx2 == 0 && ry2 == 0) bestOps = ops;\n        }\n    }\n\n    for (auto [d, p] : bestOps) {\n        cout << d << ' ' << p << '\\n';\n    }\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nstruct SimResult {\n    vector<int> cnt;\n    int end_node;\n    ll err;\n};\n\nstruct BuildResult {\n    vector<int> a, b;\n    ll approx_cost;\n};\n\nstruct Candidate {\n    vector<int> order, a, b, cnt;\n    int end_node = 0;\n    ll err = (1LL << 60);\n    ll approx_cost = (1LL << 60);\n};\n\nint N, Lw;\nvector<int> T;\n\nstatic inline ll absll(ll x) { return x >= 0 ? x : -x; }\n\nbool betterCand(const Candidate& x, const Candidate& y) {\n    if (x.err != y.err) return x.err < y.err;\n    return x.approx_cost < y.approx_cost;\n}\n\nvector<int> normalize_order(vector<int> ord) {\n    int pos = find(ord.begin(), ord.end(), 0) - ord.begin();\n    rotate(ord.begin(), ord.begin() + pos, ord.end());\n    return ord;\n}\n\nvector<int> next_from_order(const vector<int>& order) {\n    vector<int> nxt(N);\n    for (int i = 0; i < N; ++i) nxt[order[i]] = order[(i + 1) % N];\n    return nxt;\n}\n\nvector<int> prev_from_order(const vector<int>& order) {\n    vector<int> prv(N);\n    for (int i = 0; i < N; ++i) prv[order[(i + 1) % N]] = order[i];\n    return prv;\n}\n\nll calc_cost(const vector<int>& assign, const vector<int>& item, const vector<int>& need, vector<int>* load_out = nullptr) {\n    vector<int> load(N, 0);\n    for (int i = 0; i < N; ++i) load[assign[i]] += item[i];\n    ll cost = 0;\n    for (int j = 0; j < N; ++j) cost += absll((ll)load[j] - need[j]);\n    if (load_out) *load_out = load;\n    return cost;\n}\n\n// ---------- fast cycle-order surrogate ----------\nll edge_cost_fast(int i, int j, const vector<int>& est) {\n    ll half_from_i = (est[i] + 1) / 2;\n    ll cap_j = T[j] - (j == 0 ? 1 : 0);\n    if (cap_j < 0) cap_j = 0;\n    ll ideal = (cap_j + 1) / 2;\n    ll over = max(0LL, half_from_i - cap_j);\n    ll sim = absll((ll)est[i] - est[j]);\n    return over * 20 + absll(half_from_i - ideal) * 4 + sim;\n}\n\nll order_cost_fast(const vector<int>& ord, const vector<int>& est) {\n    ll c = 0;\n    for (int k = 0; k < N; ++k) {\n        int i = ord[k];\n        int j = ord[(k + 1) % N];\n        c += edge_cost_fast(i, j, est);\n    }\n    return c;\n}\n\nvector<int> mutate_order_random(const vector<int>& ord, mt19937& rng) {\n    vector<int> res = ord;\n    int op = (int)(rng() % 3);\n\n    if (op == 0) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) swap(res[x], res[y]);\n    } else if (op == 1) {\n        int x = 1 + (int)(rng() % (N - 1));\n        int y = 1 + (int)(rng() % (N - 1));\n        if (x != y) {\n            int v = res[x];\n            res.erase(res.begin() + x);\n            if (y > x) --y;\n            res.insert(res.begin() + y, v);\n        }\n    } else {\n        int l = 1 + (int)(rng() % (N - 1));\n        int r = 1 + (int)(rng() % (N - 1));\n        if (l > r) swap(l, r);\n        if (l == r) r = min(N - 1, l + 1);\n        reverse(res.begin() + l, res.begin() + r + 1);\n    }\n    return res;\n}\n\nvector<int> optimize_order_fast(vector<int> ord, const vector<int>& est, mt19937& rng, int iters, double temp0) {\n    ord = normalize_order(ord);\n    ll cur = order_cost_fast(ord, est);\n    vector<int> best = ord;\n    ll bestc = cur;\n\n    uniform_real_distribution<double> U(0.0, 1.0);\n    double temp = temp0;\n    double temp1 = 1.0;\n    double alpha = pow(temp1 / temp0, 1.0 / max(1, iters));\n\n    for (int iter = 0; iter < iters; ++iter) {\n        vector<int> cand = mutate_order_random(ord, rng);\n        ll nc = order_cost_fast(cand, est);\n        if (nc < cur || U(rng) < exp((double)(cur - nc) / max(1.0, temp))) {\n            ord.swap(cand);\n            cur = nc;\n            if (cur < bestc) {\n                bestc = cur;\n                best = ord;\n            }\n        }\n        temp *= alpha;\n    }\n    return best;\n}\n\n// ---------- assignment builders ----------\nvector<int> init_dp_partition(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N), tgt_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    iota(tgt_ord.begin(), tgt_ord.end(), 0);\n\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] < item[b];\n        return a < b;\n    });\n    sort(tgt_ord.begin(), tgt_ord.end(), [&](int a, int b) {\n        if (need[a] != need[b]) return need[a] < need[b];\n        return a < b;\n    });\n\n    vector<ll> pref(N + 1, 0);\n    for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + item[src_ord[i]];\n\n    const ll INF = (1LL << 60);\n    vector<vector<ll>> dp(N + 1, vector<ll>(N + 1, INF));\n    vector<vector<int>> par(N + 1, vector<int>(N + 1, -1));\n    dp[0][0] = 0;\n\n    for (int k = 0; k < N; ++k) {\n        for (int i = 0; i <= N; ++i) {\n            if (dp[k][i] >= INF) continue;\n            for (int j = i; j <= N; ++j) {\n                ll segsum = pref[j] - pref[i];\n                ll nd = dp[k][i] + absll(segsum - (ll)need[tgt_ord[k]]);\n                if (nd < dp[k + 1][j]) {\n                    dp[k + 1][j] = nd;\n                    par[k + 1][j] = i;\n                }\n            }\n        }\n    }\n\n    vector<int> assign(N, 0);\n    int cur = N;\n    for (int k = N - 1; k >= 0; --k) {\n        int prv = par[k + 1][cur];\n        if (prv < 0) prv = 0;\n        for (int p = prv; p < cur; ++p) assign[src_ord[p]] = tgt_ord[k];\n        cur = prv;\n    }\n    return assign;\n}\n\nvector<int> init_greedy(const vector<int>& item, const vector<int>& need) {\n    vector<int> src_ord(N);\n    iota(src_ord.begin(), src_ord.end(), 0);\n    sort(src_ord.begin(), src_ord.end(), [&](int a, int b) {\n        if (item[a] != item[b]) return item[a] > item[b];\n        return a < b;\n    });\n\n    vector<int> assign(N, 0), load(N, 0);\n\n    for (int s : src_ord) {\n        ll best_delta = (1LL << 60);\n        int best_t = 0;\n        for (int t = 0; t < N; ++t) {\n            ll before = absll((ll)load[t] - need[t]);\n            ll after = absll((ll)load[t] + item[s] - need[t]);\n            ll delta = after - before;\n            ll deficit = (ll)need[t] - load[t];\n            ll best_deficit = (ll)need[best_t] - load[best_t];\n            if (delta < best_delta ||\n                (delta == best_delta && deficit > best_deficit) ||\n                (delta == best_delta && deficit == best_deficit && t < best_t)) {\n                best_delta = delta;\n                best_t = t;\n            }\n        }\n        assign[s] = best_t;\n        load[best_t] += item[s];\n    }\n    return assign;\n}\n\nll local_search_assign(vector<int>& assign, const vector<int>& item, const vector<int>& need) {\n    vector<int> load;\n    ll total = calc_cost(assign, item, need, &load);\n\n    const int MAX_IT = 80;\n    for (int iter = 0; iter < MAX_IT; ++iter) {\n        vector<ll> base(N);\n        for (int j = 0; j < N; ++j) base[j] = absll((ll)load[j] - need[j]);\n\n        ll best_delta = 0;\n        int best_kind = 0;\n        int bi = -1, bj = -1, bk = -1;\n\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i], w = item[i];\n            if (w == 0) continue;\n            for (int v = 0; v < N; ++v) if (v != u) {\n                ll delta = 0;\n                delta += absll((ll)load[u] - w - need[u]) - base[u];\n                delta += absll((ll)load[v] + w - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 1;\n                    bi = i; bj = v;\n                }\n            }\n        }\n\n        for (int i = 0; i < N; ++i) {\n            int u = assign[i], wi = item[i];\n            for (int k = i + 1; k < N; ++k) {\n                int v = assign[k];\n                if (u == v) continue;\n                int wk = item[k];\n                ll delta = 0;\n                delta += absll((ll)load[u] - wi + wk - need[u]) - base[u];\n                delta += absll((ll)load[v] - wk + wi - need[v]) - base[v];\n                if (delta < best_delta) {\n                    best_delta = delta;\n                    best_kind = 2;\n                    bi = i; bk = k;\n                }\n            }\n        }\n\n        if (best_kind == 0) break;\n\n        if (best_kind == 1) {\n            int i = bi, v = bj;\n            int u = assign[i], w = item[i];\n            load[u] -= w;\n            load[v] += w;\n            assign[i] = v;\n            total += best_delta;\n        } else {\n            int i = bi, k = bk;\n            int u = assign[i], v = assign[k];\n            int wi = item[i], wk = item[k];\n            load[u] = load[u] - wi + wk;\n            load[v] = load[v] - wk + wi;\n            swap(assign[i], assign[k]);\n            total += best_delta;\n        }\n    }\n    return total;\n}\n\n// ---------- build graph ----------\nBuildResult build_graph(const vector<int>& order, const vector<int>& est_cnt, bool exact_end, int end_node) {\n    vector<int> nxt = next_from_order(order);\n    vector<int> prv = prev_from_order(order);\n\n    vector<int> out = est_cnt;\n    if (exact_end && 0 <= end_node && end_node < N) out[end_node]--;\n\n    vector<int> fixed_a(N), item_b(N), need(N);\n    for (int i = 0; i < N; ++i) {\n        if (out[i] < 0) out[i] = 0;\n        fixed_a[i] = (out[i] + 1) / 2;\n        item_b[i] = out[i] / 2;\n    }\n    for (int j = 0; j < N; ++j) {\n        need[j] = T[j] - (j == 0 ? 1 : 0) - fixed_a[prv[j]];\n    }\n\n    vector<int> assign1 = init_dp_partition(item_b, need);\n    ll cost1 = local_search_assign(assign1, item_b, need);\n\n    vector<int> assign2 = init_greedy(item_b, need);\n    ll cost2 = local_search_assign(assign2, item_b, need);\n\n    BuildResult res;\n    res.a = move(nxt);\n    if (cost1 <= cost2) {\n        res.b = move(assign1);\n        res.approx_cost = cost1;\n    } else {\n        res.b = move(assign2);\n        res.approx_cost = cost2;\n    }\n    return res;\n}\n\n// ---------- exact simulation ----------\nSimResult simulate_graph(const vector<int>& a, const vector<int>& b) {\n    int cnt_arr[100] = {};\n    int cur = 0, end_node = 0;\n\n    for (int week = 0; week + 1 < Lw; ++week) {\n        int c = ++cnt_arr[cur];\n        end_node = cur;\n        cur = (c & 1) ? a[cur] : b[cur];\n    }\n    ++cnt_arr[cur];\n    end_node = cur;\n\n    vector<int> cnt(N);\n    ll err = 0;\n    for (int i = 0; i < N; ++i) {\n        cnt[i] = cnt_arr[i];\n        err += absll((ll)cnt[i] - T[i]);\n    }\n    return {move(cnt), end_node, err};\n}\n\nCandidate make_candidate(const vector<int>& order, const vector<int>& a, const vector<int>& b, ll approx_cost) {\n    SimResult sr = simulate_graph(a, b);\n    Candidate c;\n    c.order = order;\n    c.a = a;\n    c.b = b;\n    c.cnt = move(sr.cnt);\n    c.end_node = sr.end_node;\n    c.err = sr.err;\n    c.approx_cost = approx_cost;\n    return c;\n}\n\nCandidate evaluate_order(const vector<int>& order, const vector<int>& init_est, bool exact_end_init, int end_init, int refine_rounds) {\n    BuildResult br = build_graph(order, init_est, exact_end_init, end_init);\n    Candidate cur = make_candidate(order, br.a, br.b, br.approx_cost);\n    Candidate best = cur;\n\n    for (int it = 0; it < refine_rounds; ++it) {\n        BuildResult br2 = build_graph(order, cur.cnt, true, cur.end_node);\n        Candidate nxt = make_candidate(order, br2.a, br2.b, br2.approx_cost);\n        if (betterCand(nxt, cur)) {\n            cur = nxt;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\nCandidate rebuild_if_better(const Candidate& base, int refine_rounds = 1) {\n    Candidate cand = evaluate_order(base.order, base.cnt, true, base.end_node, refine_rounds);\n    return betterCand(cand, base) ? cand : base;\n}\n\n// ---------- order generators ----------\nvector<int> sorted_order(bool desc) {\n    vector<int> ord(N);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return desc ? (T[a] > T[b]) : (T[a] < T[b]);\n        return a < b;\n    });\n    return normalize_order(ord);\n}\n\nvector<int> nearest_neighbor_order(int start, bool half_cost_mode) {\n    vector<int> ord;\n    vector<int> used(N, 0);\n    ord.reserve(N);\n    ord.push_back(start);\n    used[start] = 1;\n    int cur = start;\n\n    for (int step = 1; step < N; ++step) {\n        int best = -1;\n        ll best1 = (1LL << 60), best2 = (1LL << 60);\n        for (int v = 0; v < N; ++v) if (!used[v]) {\n            ll c1, c2;\n            if (!half_cost_mode) {\n                c1 = absll((ll)T[cur] - T[v]);\n                c2 = 0;\n            } else {\n                c1 = max(0, (T[cur] + 1) / 2 - T[v]);\n                c2 = absll((ll)T[cur] - T[v]);\n            }\n            if (best == -1 || c1 < best1 || (c1 == best1 && c2 < best2) || (c1 == best1 && c2 == best2 && v < best)) {\n                best = v;\n                best1 = c1;\n                best2 = c2;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return normalize_order(ord);\n}\n\nvector<int> median_out_order(const vector<int>& base_sorted) {\n    vector<int> ord;\n    ord.reserve(N);\n    int mid = N / 2;\n    ord.push_back(base_sorted[mid]);\n    for (int d = 1; (int)ord.size() < N; ++d) {\n        if (mid - d >= 0) ord.push_back(base_sorted[mid - d]);\n        if ((int)ord.size() >= N) break;\n        if (mid + d < N) ord.push_back(base_sorted[mid + d]);\n    }\n    return normalize_order(ord);\n}\n\nvector<int> alternating_low_high_order() {\n    vector<int> s(N);\n    iota(s.begin(), s.end(), 0);\n    sort(s.begin(), s.end(), [&](int a, int b) {\n        if (T[a] != T[b]) return T[a] < T[b];\n        return a < b;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    int l = 0, r = N - 1;\n    while (l <= r) {\n        ord.push_back(s[l++]);\n        if (l <= r) ord.push_back(s[r--]);\n    }\n    return normalize_order(ord);\n}\n\nvoid add_order_if_new(vector<vector<int>>& orders, set<vector<int>>& seen, vector<int> ord) {\n    ord = normalize_order(ord);\n    if (seen.insert(ord).second) orders.push_back(ord);\n}\n\n// ---------- exact local improvement on order ----------\nCandidate improve_candidate_order(Candidate start, mt19937& rng) {\n    Candidate best = start;\n    Candidate cur = start;\n    set<vector<int>> tried;\n    tried.insert(cur.order);\n\n    {\n        auto jumped = optimize_order_fast(cur.order, cur.cnt, rng, 900, 2500.0);\n        if (!tried.count(jumped)) {\n            tried.insert(jumped);\n            Candidate cand = evaluate_order(jumped, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, cur)) cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n\n    for (int iter = 0; iter < 9; ++iter) {\n        vector<int> chosen;\n        ll best_fast = (1LL << 60);\n\n        for (int t = 0; t < 5; ++t) {\n            auto m = mutate_order_random(cur.order, rng);\n            if (tried.count(m)) continue;\n            ll fc = order_cost_fast(m, cur.cnt);\n            if (fc < best_fast) {\n                best_fast = fc;\n                chosen = move(m);\n            }\n        }\n        if (chosen.empty()) continue;\n        tried.insert(chosen);\n\n        Candidate cand = evaluate_order(chosen, cur.cnt, true, cur.end_node, 1);\n        if (betterCand(cand, cur)) {\n            cur = cand;\n            if (betterCand(cur, best)) best = cur;\n        }\n    }\n    return best;\n}\n\n// ---------- end-node refinement ----------\nCandidate refine_endnode_candidate(const Candidate& base) {\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n\n    vector<int> cand_e;\n    cand_e.push_back(base.end_node);\n    cand_e.push_back(0);\n\n    vector<int> def = ids, ex = ids;\n    sort(def.begin(), def.end(), [&](int a, int b) {\n        ll ra = (ll)T[a] - base.cnt[a];\n        ll rb = (ll)T[b] - base.cnt[b];\n        if (ra != rb) return ra > rb;\n        return a < b;\n    });\n    sort(ex.begin(), ex.end(), [&](int a, int b) {\n        ll ra = (ll)base.cnt[a] - T[a];\n        ll rb = (ll)base.cnt[b] - T[b];\n        if (ra != rb) return ra > rb;\n        return a < b;\n    });\n\n    for (int i = 0; i < 8; ++i) cand_e.push_back(def[i]);\n    for (int i = 0; i < 4; ++i) cand_e.push_back(ex[i]);\n\n    sort(cand_e.begin(), cand_e.end());\n    cand_e.erase(unique(cand_e.begin(), cand_e.end()), cand_e.end());\n\n    Candidate best = base;\n    for (int e : cand_e) {\n        Candidate c = evaluate_order(base.order, base.cnt, true, e, 1);\n        if (betterCand(c, best)) best = c;\n    }\n    return best;\n}\n\n// ---------- local graph repair ----------\nstruct MoveCand {\n    ll approx_delta;\n    int type;\n    int i, v, k;\n};\n\nCandidate local_search_b_moves(Candidate cur, int rounds = 4, int exactTop = 16) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useB(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useB[i] = dep[i] / 2;\n        }\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            ll ra = (ll)T[a] - cur.cnt[a];\n            ll rb = (ll)T[b] - cur.cnt[b];\n            if (ra != rb) return ra > rb;\n            return a < b;\n        });\n\n        vector<int> tgt;\n        for (int k = 0; k < 10; ++k) tgt.push_back(ids[k]);\n        tgt.push_back(0);\n        sort(tgt.begin(), tgt.end());\n        tgt.erase(unique(tgt.begin(), tgt.end()), tgt.end());\n\n        vector<MoveCand> moves;\n        moves.reserve(N * (int)tgt.size());\n        for (int i = 0; i < N; ++i) {\n            int w = useB[i];\n            if (w == 0) continue;\n            int old = cur.b[i];\n            for (int v : tgt) {\n                if (v == old) continue;\n                ll before = absll((ll)cur.cnt[old] - T[old]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[old] - w - T[old]) + absll((ll)cur.cnt[v] + w - T[v]);\n                moves.push_back({after - before, 0, i, v, -1});\n            }\n        }\n\n        sort(moves.begin(), moves.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& mv : moves) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> nb = cur.b;\n            nb[mv.i] = mv.v;\n            SimResult sr = simulate_graph(cur.a, nb);\n            Candidate cand = cur;\n            cand.b = move(nb);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\nCandidate local_search_b_swaps(Candidate cur, int rounds = 2, int exactTop = 10) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useB(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useB[i] = dep[i] / 2;\n        }\n\n        vector<MoveCand> ops;\n        ops.reserve(N * N / 2);\n\n        for (int i = 0; i < N; ++i) {\n            if (useB[i] == 0) continue;\n            for (int k = i + 1; k < N; ++k) {\n                if (useB[k] == 0) continue;\n                int u = cur.b[i], v = cur.b[k];\n                if (u == v) continue;\n                int wi = useB[i], wk = useB[k];\n\n                ll before = absll((ll)cur.cnt[u] - T[u]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[u] - wi + wk - T[u]) + absll((ll)cur.cnt[v] - wk + wi - T[v]);\n                ops.push_back({after - before, 2, i, -1, k});\n            }\n        }\n\n        sort(ops.begin(), ops.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.k < b.k;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& op : ops) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> nb = cur.b;\n            swap(nb[op.i], nb[op.k]);\n            SimResult sr = simulate_graph(cur.a, nb);\n            Candidate cand = cur;\n            cand.b = move(nb);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n\n    return best;\n}\n\nCandidate local_search_small_a_moves(Candidate cur, int rounds = 2, int exactTop = 10) {\n    Candidate best = cur;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<int> dep = cur.cnt;\n        dep[cur.end_node]--;\n        vector<int> useA(N, 0);\n        for (int i = 0; i < N; ++i) {\n            if (dep[i] < 0) dep[i] = 0;\n            useA[i] = (dep[i] + 1) / 2;\n        }\n\n        vector<int> deficit_ids(N);\n        iota(deficit_ids.begin(), deficit_ids.end(), 0);\n        sort(deficit_ids.begin(), deficit_ids.end(), [&](int a, int b) {\n            ll ra = (ll)T[a] - cur.cnt[a];\n            ll rb = (ll)T[b] - cur.cnt[b];\n            if (ra != rb) return ra > rb;\n            return a < b;\n        });\n\n        vector<int> small_src(N);\n        iota(small_src.begin(), small_src.end(), 0);\n        sort(small_src.begin(), small_src.end(), [&](int a, int b) {\n            if (useA[a] != useA[b]) return useA[a] < useA[b];\n            return a < b;\n        });\n\n        vector<int> tgt;\n        for (int k = 0; k < 8; ++k) tgt.push_back(deficit_ids[k]);\n        tgt.push_back(0);\n        sort(tgt.begin(), tgt.end());\n        tgt.erase(unique(tgt.begin(), tgt.end()), tgt.end());\n\n        vector<MoveCand> moves;\n        moves.reserve(200);\n        int src_take = 0;\n        for (int i : small_src) {\n            if (i == 0) continue;\n            int w = useA[i];\n            if (w == 0) continue;\n            ++src_take;\n            if (src_take > 24) break;\n            int old = cur.a[i];\n            for (int v : tgt) {\n                if (v == old) continue;\n                ll before = absll((ll)cur.cnt[old] - T[old]) + absll((ll)cur.cnt[v] - T[v]);\n                ll after  = absll((ll)cur.cnt[old] - w - T[old]) + absll((ll)cur.cnt[v] + w - T[v]);\n                moves.push_back({after - before, 1, i, v, -1});\n            }\n        }\n\n        sort(moves.begin(), moves.end(), [&](const MoveCand& a, const MoveCand& b) {\n            if (a.approx_delta != b.approx_delta) return a.approx_delta < b.approx_delta;\n            if (a.i != b.i) return a.i < b.i;\n            return a.v < b.v;\n        });\n\n        Candidate best_local = cur;\n        int tried = 0;\n        for (const auto& mv : moves) {\n            if (tried >= exactTop) break;\n            ++tried;\n            vector<int> na = cur.a;\n            na[mv.i] = mv.v;\n            SimResult sr = simulate_graph(na, cur.b);\n            Candidate cand = cur;\n            cand.a = move(na);\n            cand.cnt = move(sr.cnt);\n            cand.end_node = sr.end_node;\n            cand.err = sr.err;\n            if (cand.err < best_local.err) best_local = move(cand);\n        }\n\n        if (best_local.err < cur.err) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n    return best;\n}\n\n// ---------- systematic local order search ----------\nvector<int> relocate_order(const vector<int>& ord, int i, int j) {\n    vector<int> res = ord;\n    int v = res[i];\n    res.erase(res.begin() + i);\n    if (j > i) --j;\n    res.insert(res.begin() + j, v);\n    return res;\n}\n\nvector<int> swap_order_pos(const vector<int>& ord, int i, int j) {\n    vector<int> res = ord;\n    swap(res[i], res[j]);\n    return res;\n}\n\nCandidate systematic_order_relocate_search(Candidate start, int rounds = 2, int exactTop = 6) {\n    Candidate best = start;\n    Candidate cur = start;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<pair<ll, pair<int, int>>> cand_moves;\n        cand_moves.reserve((N - 1) * (N - 2));\n\n        for (int i = 1; i < N; ++i) {\n            for (int j = 1; j < N; ++j) {\n                if (i == j) continue;\n                vector<int> ord2 = relocate_order(cur.order, i, j);\n                ll fc = order_cost_fast(ord2, cur.cnt);\n                cand_moves.push_back({fc, {i, j}});\n            }\n        }\n\n        sort(cand_moves.begin(), cand_moves.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        Candidate best_local = cur;\n        set<vector<int>> used_orders;\n        used_orders.insert(cur.order);\n\n        int tried = 0;\n        for (auto& ent : cand_moves) {\n            if (tried >= exactTop) break;\n            int i = ent.second.first;\n            int j = ent.second.second;\n            vector<int> ord2 = relocate_order(cur.order, i, j);\n            if (!used_orders.insert(ord2).second) continue;\n            ++tried;\n            Candidate cand = evaluate_order(ord2, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, best_local)) best_local = move(cand);\n        }\n\n        if (betterCand(best_local, cur)) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n\n    return best;\n}\n\nCandidate systematic_order_swap_search(Candidate start, int rounds = 1, int exactTop = 4) {\n    Candidate best = start;\n    Candidate cur = start;\n\n    for (int iter = 0; iter < rounds; ++iter) {\n        vector<pair<ll, pair<int, int>>> cand_moves;\n        cand_moves.reserve((N - 1) * (N - 2) / 2);\n\n        for (int i = 1; i < N; ++i) {\n            for (int j = i + 1; j < N; ++j) {\n                vector<int> ord2 = swap_order_pos(cur.order, i, j);\n                ll fc = order_cost_fast(ord2, cur.cnt);\n                cand_moves.push_back({fc, {i, j}});\n            }\n        }\n\n        sort(cand_moves.begin(), cand_moves.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        Candidate best_local = cur;\n        int tried = 0;\n\n        for (auto& ent : cand_moves) {\n            if (tried >= exactTop) break;\n            int i = ent.second.first;\n            int j = ent.second.second;\n            vector<int> ord2 = swap_order_pos(cur.order, i, j);\n            ++tried;\n            Candidate cand = evaluate_order(ord2, cur.cnt, true, cur.end_node, 1);\n            if (betterCand(cand, best_local)) best_local = move(cand);\n        }\n\n        if (betterCand(best_local, cur)) {\n            cur = best_local;\n            if (betterCand(cur, best)) best = cur;\n        } else {\n            break;\n        }\n    }\n\n    return best;\n}\n\nCandidate polish_order_candidate(Candidate c) {\n    c = rebuild_if_better(c, 1);\n    {\n        Candidate t = systematic_order_relocate_search(c, 2, 6);\n        if (betterCand(t, c)) c = t;\n    }\n    {\n        Candidate t = systematic_order_swap_search(c, 1, 4);\n        if (betterCand(t, c)) c = t;\n    }\n    c = rebuild_if_better(c, 1);\n    return c;\n}\n\nCandidate probe_graph_polish(Candidate c) {\n    {\n        Candidate t = local_search_b_moves(c, 1, 4);\n        if (betterCand(t, c)) c = t;\n    }\n    {\n        Candidate t = local_search_b_swaps(c, 1, 2);\n        if (betterCand(t, c)) c = t;\n    }\n    return c;\n}\n\nCandidate full_graph_polish(Candidate c) {\n    {\n        Candidate t = local_search_b_moves(c, 4, 16);\n        if (betterCand(t, c)) c = t;\n    }\n    {\n        Candidate t = local_search_b_swaps(c, 2, 10);\n        if (betterCand(t, c)) c = t;\n    }\n    c = rebuild_if_better(c, 1);\n    {\n        Candidate t = local_search_small_a_moves(c, 2, 10);\n        if (betterCand(t, c)) c = t;\n    }\n    {\n        Candidate t = local_search_b_moves(c, 2, 10);\n        if (betterCand(t, c)) c = t;\n    }\n\n    bool tail_improved = false;\n    {\n        Candidate t = local_search_b_swaps(c, 1, 6);\n        if (betterCand(t, c)) {\n            c = t;\n            tail_improved = true;\n        }\n    }\n    if (tail_improved) {\n        c = rebuild_if_better(c, 1);\n        Candidate t = local_search_b_moves(c, 1, 6);\n        if (betterCand(t, c)) {\n            c = t;\n            c = rebuild_if_better(c, 1);\n        }\n    }\n    return c;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> Lw;\n    T.resize(N);\n    for (int i = 0; i < N; ++i) cin >> T[i];\n\n    uint64_t seed = 88172645463393265ULL;\n    for (int x : T) {\n        seed ^= (uint64_t)(x + 0x9e3779b97f4a7c15ULL);\n        seed *= 1000003ULL;\n    }\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n    vector<vector<int>> seeds;\n    {\n        vector<int> desc = sorted_order(true);\n        vector<int> asc = sorted_order(false);\n\n        vector<int> orig(N), revorig(N);\n        iota(orig.begin(), orig.end(), 0);\n        revorig = orig;\n        reverse(revorig.begin(), revorig.end());\n\n        int imin = min_element(T.begin(), T.end()) - T.begin();\n        int imax = max_element(T.begin(), T.end()) - T.begin();\n\n        seeds.push_back(desc);\n        seeds.push_back(asc);\n        seeds.push_back(normalize_order(orig));\n        seeds.push_back(normalize_order(revorig));\n        seeds.push_back(nearest_neighbor_order(0, false));\n        seeds.push_back(nearest_neighbor_order(0, true));\n        seeds.push_back(nearest_neighbor_order(imin, false));\n        seeds.push_back(nearest_neighbor_order(imax, false));\n        seeds.push_back(nearest_neighbor_order(imax, true));\n        seeds.push_back(median_out_order(desc));\n        {\n            auto tmp = median_out_order(desc);\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n        seeds.push_back(alternating_low_high_order());\n        {\n            auto tmp = alternating_low_high_order();\n            reverse(tmp.begin() + 1, tmp.end());\n            seeds.push_back(normalize_order(tmp));\n        }\n    }\n\n    vector<vector<int>> orders;\n    set<vector<int>> seen;\n    for (auto s : seeds) add_order_if_new(orders, seen, s);\n    for (auto s : seeds) {\n        auto opt = optimize_order_fast(s, T, rng, 1100, 3000.0);\n        add_order_if_new(orders, seen, opt);\n    }\n    for (int rep = 0; rep < 10; ++rep) {\n        auto tmp = seeds[rng() % seeds.size()];\n        int mv = 3 + (rng() % 4);\n        for (int k = 0; k < mv; ++k) tmp = mutate_order_random(tmp, rng);\n        tmp = optimize_order_fast(tmp, T, rng, 800, 2200.0);\n        add_order_if_new(orders, seen, tmp);\n    }\n\n    vector<pair<ll, int>> rank_idx;\n    rank_idx.reserve(orders.size());\n    for (int i = 0; i < (int)orders.size(); ++i) {\n        rank_idx.push_back({order_cost_fast(orders[i], T), i});\n    }\n    sort(rank_idx.begin(), rank_idx.end());\n\n    int M = min<int>(20, rank_idx.size());\n    vector<Candidate> cand_list;\n    cand_list.reserve(M);\n\n    for (int z = 0; z < M; ++z) {\n        int idx = rank_idx[z].second;\n        cand_list.push_back(evaluate_order(orders[idx], T, false, -1, 2));\n    }\n\n    sort(cand_list.begin(), cand_list.end(), [&](const Candidate& x, const Candidate& y) {\n        return betterCand(x, y);\n    });\n\n    int topImprove = min<int>(3, cand_list.size());\n    for (int i = 0; i < topImprove; ++i) {\n        Candidate improved = improve_candidate_order(cand_list[i], rng);\n        if (betterCand(improved, cand_list[i])) cand_list[i] = improved;\n    }\n\n    sort(cand_list.begin(), cand_list.end(), [&](const Candidate& x, const Candidate& y) {\n        return betterCand(x, y);\n    });\n\n    vector<Candidate> elite;\n    int eliteK = min<int>(2, cand_list.size());\n    for (int i = 0; i < eliteK; ++i) elite.push_back(cand_list[i]);\n\n    for (int i = 0; i < eliteK; ++i) {\n        elite[i] = polish_order_candidate(elite[i]);\n    }\n\n    sort(elite.begin(), elite.end(), [&](const Candidate& x, const Candidate& y) {\n        return betterCand(x, y);\n    });\n\n    for (int i = 0; i < eliteK; ++i) {\n        elite[i] = refine_endnode_candidate(elite[i]);\n    }\n\n    sort(elite.begin(), elite.end(), [&](const Candidate& x, const Candidate& y) {\n        return betterCand(x, y);\n    });\n\n    if (eliteK >= 2 && elite[1].err <= elite[0].err + 1800) {\n        elite[0] = probe_graph_polish(elite[0]);\n        elite[1] = probe_graph_polish(elite[1]);\n        sort(elite.begin(), elite.end(), [&](const Candidate& x, const Candidate& y) {\n            return betterCand(x, y);\n        });\n    }\n\n    Candidate best = full_graph_polish(elite[0]);\n\n    for (int i = 0; i < N; ++i) {\n        cout << best.a[i] << ' ' << best.b[i] << '\\n';\n    }\n    return 0;\n}","ahc045":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 800;\nstatic constexpr double INF = 1e100;\n\nint N, M, Q, L, Wv;\nvector<int> G;\n\nint LX[MAXN], RX[MAXN], LY[MAXN], RY[MAXN];\nint SX[MAXN], SY[MAXN];\nint WX[MAXN], WY[MAXN];\nuint64_t MKEY[MAXN];\ndouble estD[MAXN][MAXN];\n\nstruct DSU {\n    vector<int> p, sz;\n    DSU() {}\n    DSU(int n) { 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), 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 GroupItem {\n    int size;\n    int id;\n};\n\nstruct QueryPlan {\n    int gid;\n    vector<int> subset;\n};\n\nstruct GroupOrderPack {\n    vector<vector<int>> ranked;\n};\n\nstatic inline long long edgeKey(int u, int v) {\n    if (u > v) swap(u, v);\n    return (static_cast<long long>(u) << 11) | v;\n}\n\nuint32_t part1by1(uint32_t x) {\n    x &= 0x0000ffffu;\n    x = (x | (x << 8)) & 0x00FF00FFu;\n    x = (x | (x << 4)) & 0x0F0F0F0Fu;\n    x = (x | (x << 2)) & 0x33333333u;\n    x = (x | (x << 1)) & 0x55555555u;\n    return x;\n}\nuint64_t mortonEncode(uint32_t x, uint32_t y) {\n    return (uint64_t)part1by1(x) | ((uint64_t)part1by1(y) << 1);\n}\n\nbool cmpMortonCity(int a, int b) {\n    if (MKEY[a] != MKEY[b]) return MKEY[a] < MKEY[b];\n    return a < b;\n}\nbool cmpXCity(int a, int b) {\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    return a < b;\n}\nbool cmpYCity(int a, int b) {\n    if (SY[a] != SY[b]) return SY[a] < SY[b];\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\nbool cmpSumCity(int a, int b) {\n    int sa = SX[a] + SY[a];\n    int sb = SX[b] + SY[b];\n    if (sa != sb) return sa < sb;\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\nbool cmpDiffCity(int a, int b) {\n    int da = SX[a] - SY[a];\n    int db = SX[b] - SY[b];\n    if (da != db) return da < db;\n    if (SX[a] != SX[b]) return SX[a] < SX[b];\n    return a < b;\n}\n\nvector<int> sort_morton(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpMortonCity);\n    return v;\n}\nvector<int> sort_x(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpXCity);\n    return v;\n}\nvector<int> sort_y(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpYCity);\n    return v;\n}\nvector<int> sort_sum(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpSumCity);\n    return v;\n}\nvector<int> sort_diff(const vector<int>& group) {\n    vector<int> v = group;\n    sort(v.begin(), v.end(), cmpDiffCity);\n    return v;\n}\n\nvector<int> nn_order(const vector<int>& group, int startCity) {\n    int g = (int)group.size();\n    vector<char> used(N, 0);\n    vector<int> ord;\n    ord.reserve(g);\n    int cur = startCity;\n    used[cur] = 1;\n    ord.push_back(cur);\n\n    for (int step = 1; step < g; step++) {\n        int best = -1;\n        double bestD = INF;\n        for (int v : group) {\n            if (used[v]) continue;\n            double d = estD[cur][v];\n            if (best == -1 || d < bestD - 1e-12 ||\n                (fabs(d - bestD) <= 1e-12 && cmpMortonCity(v, best))) {\n                best = v;\n                bestD = d;\n            }\n        }\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n    return ord;\n}\n\ndouble mst_cost_slice(const vector<int>& ord, int st, int len) {\n    if (len <= 1) return 0.0;\n    double md[16];\n    bool used[16];\n    for (int i = 0; i < len; i++) {\n        md[i] = INF;\n        used[i] = false;\n    }\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < len; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < len; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = true;\n        total += bv;\n        int u = ord[st + bi];\n        for (int j = 0; j < len; j++) {\n            if (!used[j]) {\n                double w = estD[u][ord[st + j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\ndouble chain_cover_cost(const vector<int>& ord) {\n    int g = (int)ord.size();\n    if (g <= 1) return 0.0;\n    if (g == 2) return estD[ord[0]][ord[1]];\n    if (g <= L) return mst_cost_slice(ord, 0, g);\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = estD[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<double> dp(remain + 1, INF), ndp(remain + 1, INF);\n    dp[0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        fill(ndp.begin(), ndp.end(), INF);\n        for (int p = 0; p <= remain; p++) {\n            if (dp[p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[p] + wcost[p][t];\n                if (cand < ndp[np]) ndp[np] = cand;\n            }\n        }\n        dp.swap(ndp);\n    }\n    return dp[remain];\n}\n\nvector<int> chain_cover_reconstruct_adds(const vector<int>& ord) {\n    int g = (int)ord.size();\n    vector<int> adds;\n    if (g <= 2) return adds;\n    if (g <= L) {\n        adds.push_back(g - 1);\n        return adds;\n    }\n\n    int remain = g - 1;\n    int K = (remain + (L - 2)) / (L - 1);\n\n    vector<array<double, 16>> wcost(remain);\n    for (int p = 0; p < remain; p++) {\n        wcost[p].fill(INF);\n        int maxT = min(L - 1, remain - p);\n        for (int t = 1; t <= maxT; t++) {\n            if (t == 1) wcost[p][t] = estD[ord[p]][ord[p + 1]];\n            else wcost[p][t] = mst_cost_slice(ord, p, t + 1);\n        }\n    }\n\n    vector<vector<double>> dp(K + 1, vector<double>(remain + 1, INF));\n    vector<vector<int>> parT(K + 1, vector<int>(remain + 1, -1));\n    vector<vector<int>> parP(K + 1, vector<int>(remain + 1, -1));\n    dp[0][0] = 0.0;\n\n    for (int b = 0; b < K; b++) {\n        for (int p = 0; p <= remain; p++) {\n            if (dp[b][p] >= INF / 2) continue;\n            int remBlocks = K - b - 1;\n            int maxT = min(L - 1, remain - p);\n            for (int t = 1; t <= maxT; t++) {\n                int np = p + t;\n                int rem = remain - np;\n                if (rem < remBlocks) continue;\n                if (rem > remBlocks * (L - 1)) continue;\n                double cand = dp[b][p] + wcost[p][t];\n                if (cand < dp[b + 1][np]) {\n                    dp[b + 1][np] = cand;\n                    parT[b + 1][np] = t;\n                    parP[b + 1][np] = p;\n                }\n            }\n        }\n    }\n\n    int p = remain;\n    for (int b = K; b >= 1; b--) {\n        int t = parT[b][p];\n        if (t < 0) break;\n        adds.push_back(t);\n        p = parP[b][p];\n    }\n    reverse(adds.begin(), adds.end());\n    return adds;\n}\n\n// Full cover blocks, includes size-2 blocks.\nvector<vector<int>> gen_dp_cover_blocks_all(const vector<int>& ord) {\n    int g = (int)ord.size();\n    vector<vector<int>> res;\n    if (g <= 1) return res;\n    if (g <= L) {\n        res.push_back(ord);\n        return res;\n    }\n    auto adds = chain_cover_reconstruct_adds(ord);\n    int pos = 0;\n    for (int t : adds) {\n        int sz = t + 1;\n        res.emplace_back(ord.begin() + pos, ord.begin() + pos + sz);\n        pos += t;\n    }\n    return res;\n}\n\n// Query windows only, skip size-2.\nvector<vector<int>> gen_dp_cover_windows(const vector<int>& ord) {\n    auto all = gen_dp_cover_blocks_all(ord);\n    vector<vector<int>> res;\n    for (auto& v : all) if ((int)v.size() >= 3) res.push_back(v);\n    return res;\n}\n\nvector<vector<int>> gen_regular_windows(const vector<int>& ord, int offset) {\n    int g = (int)ord.size();\n    vector<vector<int>> res;\n    if (g <= L) return res;\n    if (offset < 0 || offset >= (L - 1)) return res;\n    for (int s = offset; s + L <= g; s += (L - 1)) {\n        res.emplace_back(ord.begin() + s, ord.begin() + s + L);\n    }\n    return res;\n}\n\ndouble complete_mst_cost(const vector<int>& group) {\n    int g = (int)group.size();\n    if (g <= 1) return 0.0;\n    vector<double> md(g, INF);\n    vector<char> used(g, 0);\n    md[0] = 0.0;\n    double total = 0.0;\n    for (int it = 0; it < g; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < g; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = 1;\n        total += bv;\n        int u = group[bi];\n        for (int j = 0; j < g; j++) {\n            if (!used[j]) {\n                double w = estD[u][group[j]];\n                if (w < md[j]) md[j] = w;\n            }\n        }\n    }\n    return total;\n}\n\npair<double, vector<pair<int,int>>> complete_mst_edges(const vector<int>& group) {\n    int g = (int)group.size();\n    if (g <= 1) return {0.0, {}};\n    vector<double> md(g, INF);\n    vector<int> par(g, -1);\n    vector<char> used(g, 0);\n    md[0] = 0.0;\n    double total = 0.0;\n    vector<pair<int,int>> edges;\n    edges.reserve(g - 1);\n\n    for (int it = 0; it < g; it++) {\n        int bi = -1;\n        double bv = INF;\n        for (int i = 0; i < g; i++) {\n            if (!used[i] && md[i] < bv) {\n                bv = md[i];\n                bi = i;\n            }\n        }\n        used[bi] = 1;\n        total += bv;\n        if (par[bi] != -1) {\n            int a = group[bi], b = group[par[bi]];\n            if (a > b) swap(a, b);\n            edges.push_back({a, b});\n        }\n        int u = group[bi];\n        for (int j = 0; j < g; j++) {\n            if (!used[j]) {\n                double w = estD[u][group[j]];\n                if (w < md[j]) {\n                    md[j] = w;\n                    par[j] = bi;\n                }\n            }\n        }\n    }\n    return {total, edges};\n}\n\nvector<int> mst_preorder_order(const vector<int>& group, const vector<pair<int,int>>& mstEdges) {\n    int g = (int)group.size();\n    if (g <= 2) return group;\n\n    vector<int> pos(N, -1);\n    for (int i = 0; i < g; i++) pos[group[i]] = i;\n\n    vector<vector<int>> adj(g);\n    for (auto [a, b] : mstEdges) {\n        int ia = pos[a], ib = pos[b];\n        if (ia >= 0 && ib >= 0) {\n            adj[ia].push_back(ib);\n            adj[ib].push_back(ia);\n        }\n    }\n\n    int root = 0;\n    for (int i = 1; i < g; i++) {\n        if (cmpMortonCity(group[i], group[root])) root = i;\n    }\n\n    for (int i = 0; i < g; i++) {\n        sort(adj[i].begin(), adj[i].end(), [&](int x, int y) {\n            return cmpMortonCity(group[x], group[y]);\n        });\n    }\n\n    vector<int> ord;\n    ord.reserve(g);\n    vector<int> parent(g, -1), it(g, 0), st;\n    st.push_back(root);\n    parent[root] = -2;\n\n    while (!st.empty()) {\n        int u = st.back();\n        if (it[u] == 0) ord.push_back(group[u]);\n        if (it[u] == (int)adj[u].size()) {\n            st.pop_back();\n            continue;\n        }\n        int v = adj[u][it[u]++];\n        if (v == parent[u]) continue;\n        parent[v] = u;\n        st.push_back(v);\n    }\n    return ord;\n}\n\ndouble span_cost_bbox(int dx, int dy, int cnt, int mode) {\n    double base = (mode == 0) ? (double)(dx + dy) : sqrt((double)dx * dx + (double)dy * dy);\n    return base * sqrt((double)cnt);\n}\n\nvoid kd_rec(const vector<int>& pts, const vector<GroupItem>& items,\n            vector<vector<int>>& ans, int mode) {\n    if ((int)items.size() == 1) {\n        ans[items[0].id] = pts;\n        return;\n    }\n\n    int n = (int)pts.size();\n    int m = (int)items.size();\n\n    vector<vector<char>> poss(m + 1, vector<char>(n + 1, 0));\n    poss[0][0] = 1;\n    for (int i = 0; i < m; i++) {\n        int sz = items[i].size;\n        for (int s = 0; s <= n; s++) {\n            if (!poss[i][s]) continue;\n            poss[i + 1][s] = 1;\n            if (s + sz <= n) poss[i + 1][s + sz] = 1;\n        }\n    }\n\n    vector<int> ordx = pts, ordy = pts;\n    sort(ordx.begin(), ordx.end(), cmpXCity);\n    sort(ordy.begin(), ordy.end(), cmpYCity);\n\n    vector<int> pxMinY(n), pxMaxY(n), sxMinY(n), sxMaxY(n);\n    vector<int> pyMinX(n), pyMaxX(n), syMinX(n), syMaxX(n);\n\n    for (int i = 0; i < n; i++) {\n        int v = ordx[i];\n        if (i == 0) pxMinY[i] = pxMaxY[i] = SY[v];\n        else {\n            pxMinY[i] = min(pxMinY[i - 1], SY[v]);\n            pxMaxY[i] = max(pxMaxY[i - 1], SY[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordx[i];\n        if (i == n - 1) sxMinY[i] = sxMaxY[i] = SY[v];\n        else {\n            sxMinY[i] = min(sxMinY[i + 1], SY[v]);\n            sxMaxY[i] = max(sxMaxY[i + 1], SY[v]);\n        }\n    }\n\n    for (int i = 0; i < n; i++) {\n        int v = ordy[i];\n        if (i == 0) pyMinX[i] = pyMaxX[i] = SX[v];\n        else {\n            pyMinX[i] = min(pyMinX[i - 1], SX[v]);\n            pyMaxX[i] = max(pyMaxX[i - 1], SX[v]);\n        }\n    }\n    for (int i = n - 1; i >= 0; i--) {\n        int v = ordy[i];\n        if (i == n - 1) syMinX[i] = syMaxX[i] = SX[v];\n        else {\n            syMinX[i] = min(syMinX[i + 1], SX[v]);\n            syMaxX[i] = max(syMaxX[i + 1], SX[v]);\n        }\n    }\n\n    vector<double> pxSX(n + 1, 0), pxSY(n + 1, 0), pxSXX(n + 1, 0), pxSYY(n + 1, 0);\n    vector<double> pySX(n + 1, 0), pySY(n + 1, 0), pySXX(n + 1, 0), pySYY(n + 1, 0);\n    for (int i = 0; i < n; i++) {\n        int vx = ordx[i], vy = ordy[i];\n        pxSX[i + 1] = pxSX[i] + SX[vx];\n        pxSY[i + 1] = pxSY[i] + SY[vx];\n        pxSXX[i + 1] = pxSXX[i] + 1.0 * SX[vx] * SX[vx];\n        pxSYY[i + 1] = pxSYY[i] + 1.0 * SY[vx] * SY[vx];\n\n        pySX[i + 1] = pySX[i] + SX[vy];\n        pySY[i + 1] = pySY[i] + SY[vy];\n        pySXX[i + 1] = pySXX[i] + 1.0 * SX[vy] * SX[vy];\n        pySYY[i + 1] = pySYY[i] + 1.0 * SY[vy] * SY[vy];\n    }\n\n    auto sse_cost = [&](const vector<double>& SXs, const vector<double>& SYs,\n                        const vector<double>& SXXs, const vector<double>& SYYs,\n                        int l, int r) -> double {\n        int cnt = r - l;\n        if (cnt <= 1) return 0.0;\n        double sumx = SXs[r] - SXs[l];\n        double sumy = SYs[r] - SYs[l];\n        double sumxx = SXXs[r] - SXXs[l];\n        double sumyy = SYYs[r] - SYYs[l];\n        return (sumxx - sumx * sumx / cnt) + (sumyy - sumy * sumy / cnt);\n    };\n\n    double bestScore = INF;\n    int bestS = -1;\n    int bestAxis = 0;\n\n    for (int s = 1; s < n; s++) {\n        if (!poss[m][s]) continue;\n\n        double scoreX, scoreY;\n        if (mode <= 1) {\n            int ldx = SX[ordx[s - 1]] - SX[ordx[0]];\n            int ldy = pxMaxY[s - 1] - pxMinY[s - 1];\n            int rdx = SX[ordx[n - 1]] - SX[ordx[s]];\n            int rdy = sxMaxY[s] - sxMinY[s];\n            scoreX = span_cost_bbox(ldx, ldy, s, mode) + span_cost_bbox(rdx, rdy, n - s, mode);\n\n            int ldy2 = SY[ordy[s - 1]] - SY[ordy[0]];\n            int ldx2 = pyMaxX[s - 1] - pyMinX[s - 1];\n            int rdy2 = SY[ordy[n - 1]] - SY[ordy[s]];\n            int rdx2 = syMaxX[s] - syMinX[s];\n            scoreY = span_cost_bbox(ldx2, ldy2, s, mode) + span_cost_bbox(rdx2, rdy2, n - s, mode);\n        } else {\n            scoreX = sse_cost(pxSX, pxSY, pxSXX, pxSYY, 0, s) +\n                     sse_cost(pxSX, pxSY, pxSXX, pxSYY, s, n);\n            scoreY = sse_cost(pySX, pySY, pySXX, pySYY, 0, s) +\n                     sse_cost(pySX, pySY, pySXX, pySYY, s, n);\n        }\n\n        if (scoreX < bestScore - 1e-9 ||\n            (fabs(scoreX - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n            bestScore = scoreX;\n            bestS = s;\n            bestAxis = 0;\n        }\n        if (scoreY < bestScore - 1e-9 ||\n            (fabs(scoreY - bestScore) <= 1e-9 && (bestS == -1 || abs(n - 2 * s) < abs(n - 2 * bestS)))) {\n            bestScore = scoreY;\n            bestS = s;\n            bestAxis = 1;\n        }\n    }\n\n    if (bestS == -1) {\n        bestS = n / 2;\n        bestAxis = 0;\n    }\n\n    vector<GroupItem> leftItems, rightItems;\n    int sum = bestS;\n    for (int i = m - 1; i >= 0; i--) {\n        int sz = items[i].size;\n        if (sum >= sz && poss[i][sum - sz]) {\n            leftItems.push_back(items[i]);\n            sum -= sz;\n        } else {\n            rightItems.push_back(items[i]);\n        }\n    }\n    reverse(leftItems.begin(), leftItems.end());\n    reverse(rightItems.begin(), rightItems.end());\n\n    const vector<int>& ord = (bestAxis == 0 ? ordx : ordy);\n    vector<int> leftPts(ord.begin(), ord.begin() + bestS);\n    vector<int> rightPts(ord.begin() + bestS, ord.end());\n\n    kd_rec(leftPts, leftItems, ans, mode);\n    kd_rec(rightPts, rightItems, ans, mode);\n}\n\nvector<vector<int>> makeKD(int mode, const vector<int>& itemOrder) {\n    vector<vector<int>> ans(M);\n    vector<int> pts(N);\n    iota(pts.begin(), pts.end(), 0);\n    vector<GroupItem> items;\n    items.reserve(M);\n    for (int gid : itemOrder) items.push_back({G[gid], gid});\n    kd_rec(pts, items, ans, mode);\n    return ans;\n}\n\nvector<vector<int>> makeContiguous(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n    vector<vector<int>> groups(M);\n    int pos = 0;\n    for (int gid : groupOrder) {\n        groups[gid] = vector<int>(cityOrder.begin() + pos, cityOrder.begin() + pos + G[gid]);\n        pos += G[gid];\n    }\n    return groups;\n}\n\ndouble eval_grouping(const vector<vector<int>>& groups) {\n    double sc = 0.0;\n    for (int gid = 0; gid < M; gid++) sc += complete_mst_cost(groups[gid]);\n    return sc;\n}\n\nvector<pair<int,int>> ask(const vector<int>& sub) {\n    cout << \"? \" << sub.size();\n    for (int v : sub) cout << ' ' << v;\n    cout << '\\n';\n    cout.flush();\n\n    vector<pair<int,int>> ret;\n    ret.reserve((int)sub.size() - 1);\n    for (int i = 0; i < (int)sub.size() - 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.push_back({a, b});\n    }\n    return ret;\n}\n\nGroupOrderPack make_group_orders(const vector<int>& group, const vector<pair<int,int>>& mstEdges) {\n    GroupOrderPack pack;\n    int g = (int)group.size();\n    if (g <= 2) {\n        pack.ranked.push_back(group);\n        return pack;\n    }\n\n    vector<vector<int>> cand;\n    auto add_ord = [&](const vector<int>& ord) {\n        for (const auto& ex : cand) if (ex == ord) return;\n        cand.push_back(ord);\n    };\n\n    auto mort = sort_morton(group);\n    auto xord = sort_x(group);\n    auto yord = sort_y(group);\n    auto sord = sort_sum(group);\n    auto dord = sort_diff(group);\n    auto treeord = mst_preorder_order(group, mstEdges);\n\n    add_ord(mort);    { auto t = mort; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(xord);    { auto t = xord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(yord);    { auto t = yord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(sord);    { auto t = sord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(dord);    { auto t = dord; reverse(t.begin(), t.end()); add_ord(t); }\n    add_ord(treeord); { auto t = treeord; reverse(t.begin(), t.end()); add_ord(t); }\n\n    int leftmost = *min_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n    int rightmost = *max_element(group.begin(), group.end(), [](int a, int b) {\n        if (SX[a] != SX[b]) return SX[a] < SX[b];\n        if (SY[a] != SY[b]) return SY[a] < SY[b];\n        return a < b;\n    });\n\n    {\n        auto nnL = nn_order(group, leftmost);\n        add_ord(nnL);\n        auto rev = nnL; reverse(rev.begin(), rev.end()); add_ord(rev);\n    }\n    if (rightmost != leftmost) {\n        auto nnR = nn_order(group, rightmost);\n        add_ord(nnR);\n        auto rev = nnR; reverse(rev.begin(), rev.end()); add_ord(rev);\n    }\n\n    vector<pair<double,int>> scored;\n    for (int i = 0; i < (int)cand.size(); i++) {\n        scored.push_back({chain_cover_cost(cand[i]), i});\n    }\n    sort(scored.begin(), scored.end());\n\n    for (auto [c, idx] : scored) pack.ranked.push_back(cand[idx]);\n    return pack;\n}\n\ndouble centroid_proxy_cost(int city, int gid,\n                           const vector<long long>& sumX,\n                           const vector<long long>& sumY,\n                           const vector<int>& gsz) {\n    double cx = (double)sumX[gid] / gsz[gid];\n    double cy = (double)sumY[gid] / gsz[gid];\n    double dx = SX[city] - cx;\n    double dy = SY[city] - cy;\n    return dx * dx + dy * dy;\n}\n\nvoid improve_grouping_swaps(vector<vector<int>>& groups,\n                            const vector<int>& cityMort,\n                            const vector<int>& cityX,\n                            const vector<int>& cityY,\n                            const vector<int>& cityS,\n                            const vector<int>& cityD) {\n    vector<int> cityGroup(N), posInGroup(N), gsz(M);\n    vector<long long> sumX(M, 0), sumY(M, 0);\n    vector<double> gcost(M, 0.0);\n\n    int maxG = 0;\n    for (int gid = 0; gid < M; gid++) {\n        gsz[gid] = (int)groups[gid].size();\n        maxG = max(maxG, gsz[gid]);\n        for (int i = 0; i < gsz[gid]; i++) {\n            int v = groups[gid][i];\n            cityGroup[v] = gid;\n            posInGroup[v] = i;\n            sumX[gid] += SX[v];\n            sumY[gid] += SY[v];\n        }\n        gcost[gid] = complete_mst_cost(groups[gid]);\n    }\n\n    vector<pair<double, pair<int,int>>> candPairs;\n    candPairs.reserve(60000);\n    unordered_set<long long> seen;\n    seen.reserve(70000);\n\n    auto add_pair = [&](int u, int v) {\n        if (u == v) return;\n        if (u > v) swap(u, v);\n        long long key = edgeKey(u, v);\n        if (seen.insert(key).second) {\n            candPairs.push_back({estD[u][v], {u, v}});\n        }\n    };\n\n    auto add_by_order = [&](const vector<int>& ord, int rad) {\n        int n = (int)ord.size();\n        for (int i = 0; i < n; i++) {\n            for (int d = 1; d <= rad; d++) {\n                if (i + d >= n) break;\n                add_pair(ord[i], ord[i + d]);\n            }\n        }\n    };\n\n    add_by_order(cityMort, 6);\n    add_by_order(cityX, 4);\n    add_by_order(cityY, 4);\n    add_by_order(cityS, 4);\n    add_by_order(cityD, 4);\n\n    const int GLOBAL_K = 12;\n    for (int u = 0; u < N; u++) {\n        vector<pair<double,int>> tmp;\n        tmp.reserve(N - 1);\n        for (int v = 0; v < N; v++) {\n            if (u == v) continue;\n            tmp.push_back({estD[u][v], v});\n        }\n        int lim = min(GLOBAL_K, (int)tmp.size());\n        if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n        for (int i = 0; i < lim; i++) add_pair(u, tmp[i].second);\n    }\n\n    const int KGROUP = 3;\n    for (int u = 0; u < N; u++) {\n        int gu = cityGroup[u];\n        vector<pair<double,int>> nearGroups;\n        nearGroups.reserve(M - 1);\n        for (int gv = 0; gv < M; gv++) {\n            if (gv == gu) continue;\n            double cx = (double)sumX[gv] / gsz[gv];\n            double cy = (double)sumY[gv] / gsz[gv];\n            double dx = SX[u] - cx;\n            double dy = SY[u] - cy;\n            nearGroups.push_back({dx * dx + dy * dy, gv});\n        }\n        int glim = min(KGROUP, (int)nearGroups.size());\n        if ((int)nearGroups.size() > glim) {\n            nth_element(nearGroups.begin(), nearGroups.begin() + glim, nearGroups.end());\n        }\n        for (int it = 0; it < glim; it++) {\n            int gv = nearGroups[it].second;\n            int best1 = -1, best2 = -1;\n            double bestD1 = INF, bestD2 = INF;\n            for (int v : groups[gv]) {\n                double d1 = estD[u][v];\n                if (d1 < bestD1) {\n                    bestD1 = d1;\n                    best1 = v;\n                }\n                double d2 = centroid_proxy_cost(v, gu, sumX, sumY, gsz)\n                          - centroid_proxy_cost(v, gv, sumX, sumY, gsz);\n                if (d2 < bestD2) {\n                    bestD2 = d2;\n                    best2 = v;\n                }\n            }\n            if (best1 != -1) add_pair(u, best1);\n            if (best2 != -1) add_pair(u, best2);\n        }\n    }\n\n    sort(candPairs.begin(), candPairs.end(),\n         [&](const auto& a, const auto& b) {\n             if (fabs(a.first - b.first) > 1e-12) return a.first < b.first;\n             if (a.second.first != b.second.first) return a.second.first < b.second.first;\n             return a.second.second < b.second.second;\n         });\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n    };\n\n    double budgetMs = 320.0;\n    if (maxG >= 200) budgetMs = 250.0;\n    else if (maxG >= 120) budgetMs = 285.0;\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (auto& cp : candPairs) {\n            if (elapsed_ms() > budgetMs) return;\n\n            int u = cp.second.first;\n            int v = cp.second.second;\n            int gu = cityGroup[u];\n            int gv = cityGroup[v];\n            if (gu == gv) continue;\n\n            int sa = gsz[gu];\n            int sb = gsz[gv];\n\n            double oldP = centroid_proxy_cost(u, gu, sumX, sumY, gsz)\n                        + centroid_proxy_cost(v, gv, sumX, sumY, gsz);\n            double newP = centroid_proxy_cost(v, gu, sumX, sumY, gsz)\n                        + centroid_proxy_cost(u, gv, sumX, sumY, gsz);\n\n            bool small = (sa + sb <= 20 || sa <= 8 || sb <= 8);\n            long long weight = 1LL * sa * sa + 1LL * sb * sb;\n\n            if (!small && newP >= oldP * 0.988) continue;\n            if (weight > 20000 && newP >= oldP * 0.94) continue;\n            if (weight > 80000 && newP >= oldP * 0.84) continue;\n\n            int pu = posInGroup[u];\n            int pv = posInGroup[v];\n\n            vector<int> A2 = groups[gu];\n            vector<int> B2 = groups[gv];\n            A2[pu] = v;\n            B2[pv] = u;\n\n            double newA = complete_mst_cost(A2);\n            double newB = complete_mst_cost(B2);\n\n            if (newA + newB + 1e-9 < gcost[gu] + gcost[gv]) {\n                groups[gu][pu] = v;\n                groups[gv][pv] = u;\n\n                cityGroup[v] = gu;\n                posInGroup[v] = pu;\n                cityGroup[u] = gv;\n                posInGroup[u] = pv;\n\n                sumX[gu] += SX[v] - SX[u];\n                sumY[gu] += SY[v] - SY[u];\n                sumX[gv] += SX[u] - SX[v];\n                sumY[gv] += SY[u] - SY[v];\n\n                gcost[gu] = newA;\n                gcost[gv] = newB;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n}\n\nvoid improve_grouping_pairwise(vector<vector<int>>& groups) {\n    vector<int> cityGroup(N), posInGroup(N), gsz(M);\n    vector<long long> sumX(M, 0), sumY(M, 0);\n    vector<double> gcost(M, 0.0);\n\n    for (int gid = 0; gid < M; gid++) {\n        gsz[gid] = (int)groups[gid].size();\n        for (int i = 0; i < gsz[gid]; i++) {\n            int v = groups[gid][i];\n            cityGroup[v] = gid;\n            posInGroup[v] = i;\n            sumX[gid] += SX[v];\n            sumY[gid] += SY[v];\n        }\n        gcost[gid] = complete_mst_cost(groups[gid]);\n    }\n\n    vector<pair<double, pair<int,int>>> groupPairs;\n    unordered_set<long long> seen;\n    const int NEAR_G = 4;\n\n    for (int ga = 0; ga < M; ga++) {\n        vector<pair<double,int>> tmp;\n        tmp.reserve(M - 1);\n        double cax = (double)sumX[ga] / gsz[ga];\n        double cay = (double)sumY[ga] / gsz[ga];\n        for (int gb = 0; gb < M; gb++) if (gb != ga) {\n            double cbx = (double)sumX[gb] / gsz[gb];\n            double cby = (double)sumY[gb] / gsz[gb];\n            double dx = cax - cbx, dy = cay - cby;\n            tmp.push_back({dx * dx + dy * dy, gb});\n        }\n        int lim = min(NEAR_G, (int)tmp.size());\n        if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n        for (int i = 0; i < lim; i++) {\n            int gb = tmp[i].second;\n            int x = min(ga, gb), y = max(ga, gb);\n            long long key = 1LL * x * M + y;\n            if (seen.insert(key).second) {\n                groupPairs.push_back({tmp[i].first, {x, y}});\n            }\n        }\n    }\n\n    sort(groupPairs.begin(), groupPairs.end());\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n    };\n    double budgetMs = 100.0;\n\n    auto shortlist = [&](int ga, int gb) -> vector<int> {\n        vector<pair<double,int>> byDelta, byOwn;\n        for (int u : groups[ga]) {\n            double oldc = centroid_proxy_cost(u, ga, sumX, sumY, gsz);\n            double newc = centroid_proxy_cost(u, gb, sumX, sumY, gsz);\n            byDelta.push_back({newc - oldc, u});\n            byOwn.push_back({-oldc, u});\n        }\n        sort(byDelta.begin(), byDelta.end());\n        sort(byOwn.begin(), byOwn.end());\n\n        vector<int> res;\n        auto add = [&](int u) {\n            for (int x : res) if (x == u) return;\n            res.push_back(u);\n        };\n        for (int i = 0; i < min(5, (int)byDelta.size()); i++) add(byDelta[i].second);\n        for (int i = 0; i < min(3, (int)byOwn.size()); i++) add(byOwn[i].second);\n        return res;\n    };\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (auto& gp : groupPairs) {\n            if (elapsed_ms() > budgetMs) return;\n\n            int ga = gp.second.first;\n            int gb = gp.second.second;\n            double oldPair = gcost[ga] + gcost[gb];\n\n            auto A = shortlist(ga, gb);\n            auto B = shortlist(gb, ga);\n            if (A.empty() || B.empty()) continue;\n\n            double bestImp = 0.0;\n            int bestu = -1, bestv = -1;\n            double bestA = 0.0, bestB = 0.0;\n\n            for (int u : A) {\n                for (int v : B) {\n                    double oldP = centroid_proxy_cost(u, ga, sumX, sumY, gsz)\n                                + centroid_proxy_cost(v, gb, sumX, sumY, gsz);\n                    double newP = centroid_proxy_cost(v, ga, sumX, sumY, gsz)\n                                + centroid_proxy_cost(u, gb, sumX, sumY, gsz);\n                    if (newP >= oldP * 0.997 && gsz[ga] + gsz[gb] > 20) continue;\n\n                    int pu = posInGroup[u];\n                    int pv = posInGroup[v];\n\n                    vector<int> A2 = groups[ga];\n                    vector<int> B2 = groups[gb];\n                    A2[pu] = v;\n                    B2[pv] = u;\n\n                    double nA = complete_mst_cost(A2);\n                    double nB = complete_mst_cost(B2);\n                    double imp = oldPair - (nA + nB);\n                    if (imp > bestImp + 1e-9) {\n                        bestImp = imp;\n                        bestu = u;\n                        bestv = v;\n                        bestA = nA;\n                        bestB = nB;\n                    }\n                }\n            }\n\n            if (bestImp > 1e-9) {\n                int pu = posInGroup[bestu];\n                int pv = posInGroup[bestv];\n\n                groups[ga][pu] = bestv;\n                groups[gb][pv] = bestu;\n\n                cityGroup[bestv] = ga;\n                posInGroup[bestv] = pu;\n                cityGroup[bestu] = gb;\n                posInGroup[bestu] = pv;\n\n                sumX[ga] += SX[bestv] - SX[bestu];\n                sumY[ga] += SY[bestv] - SY[bestu];\n                sumX[gb] += SX[bestu] - SX[bestv];\n                sumY[gb] += SY[bestu] - SY[bestv];\n\n                gcost[ga] = bestA;\n                gcost[gb] = bestB;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n}\n\nvoid improve_grouping_subset_exchange(vector<vector<int>>& groups) {\n    vector<int> cityGroup(N), posInGroup(N), gsz(M);\n    vector<long long> sumX(M, 0), sumY(M, 0);\n    vector<double> gcost(M, 0.0);\n\n    for (int gid = 0; gid < M; gid++) {\n        gsz[gid] = (int)groups[gid].size();\n        for (int i = 0; i < gsz[gid]; i++) {\n            int v = groups[gid][i];\n            cityGroup[v] = gid;\n            posInGroup[v] = i;\n            sumX[gid] += SX[v];\n            sumY[gid] += SY[v];\n        }\n        gcost[gid] = complete_mst_cost(groups[gid]);\n    }\n\n    vector<pair<double, pair<int,int>>> groupPairs;\n    unordered_set<long long> seen;\n    const int NEAR_G = 3;\n\n    for (int ga = 0; ga < M; ga++) {\n        vector<pair<double,int>> tmp;\n        tmp.reserve(M - 1);\n        double cax = (double)sumX[ga] / gsz[ga];\n        double cay = (double)sumY[ga] / gsz[ga];\n        for (int gb = 0; gb < M; gb++) if (gb != ga) {\n            double cbx = (double)sumX[gb] / gsz[gb];\n            double cby = (double)sumY[gb] / gsz[gb];\n            double dx = cax - cbx, dy = cay - cby;\n            tmp.push_back({dx * dx + dy * dy, gb});\n        }\n        int lim = min(NEAR_G, (int)tmp.size());\n        if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n        for (int i = 0; i < lim; i++) {\n            int gb = tmp[i].second;\n            int x = min(ga, gb), y = max(ga, gb);\n            long long key = 1LL * x * M + y;\n            if (seen.insert(key).second) {\n                groupPairs.push_back({tmp[i].first, {x, y}});\n            }\n        }\n    }\n\n    sort(groupPairs.begin(), groupPairs.end());\n\n    auto shortlist = [&](int ga, int gb, int lim) -> vector<int> {\n        vector<pair<double,int>> byDelta, byOwn;\n        for (int u : groups[ga]) {\n            double oldc = centroid_proxy_cost(u, ga, sumX, sumY, gsz);\n            double newc = centroid_proxy_cost(u, gb, sumX, sumY, gsz);\n            byDelta.push_back({newc - oldc, u});\n            byOwn.push_back({-oldc, u});\n        }\n        sort(byDelta.begin(), byDelta.end());\n        sort(byOwn.begin(), byOwn.end());\n\n        vector<int> res;\n        auto add = [&](int u) {\n            for (int x : res) if (x == u) return;\n            res.push_back(u);\n        };\n        for (int i = 0; i < min(lim, (int)byDelta.size()); i++) add(byDelta[i].second);\n        for (int i = 0; i < min(2, (int)byOwn.size()) && (int)res.size() < lim; i++) add(byOwn[i].second);\n        return res;\n    };\n\n    auto start = chrono::steady_clock::now();\n    auto elapsed_ms = [&]() -> double {\n        return chrono::duration<double, milli>(chrono::steady_clock::now() - start).count();\n    };\n    double budgetMs = 110.0;\n\n    for (int pass = 0; pass < 2; pass++) {\n        bool any = false;\n        for (auto& gp : groupPairs) {\n            if (elapsed_ms() > budgetMs) return;\n\n            int ga = gp.second.first;\n            int gb = gp.second.second;\n\n            int limA = 3, limB = 3;\n            if (gsz[ga] + gsz[gb] <= 20) limA = limB = 4;\n\n            auto A = shortlist(ga, gb, limA);\n            auto B = shortlist(gb, ga, limB);\n            if (A.empty() || B.empty()) continue;\n\n            int ka = (int)A.size();\n            int kb = (int)B.size();\n            int s = ka + kb;\n            if (s > 10) continue;\n\n            vector<int> U;\n            U.reserve(s);\n            for (int x : A) U.push_back(x);\n            for (int x : B) U.push_back(x);\n\n            vector<int> posA, posB;\n            posA.reserve(ka);\n            posB.reserve(kb);\n            for (int x : A) posA.push_back(posInGroup[x]);\n            for (int x : B) posB.push_back(posInGroup[x]);\n\n            double oldPair = gcost[ga] + gcost[gb];\n            double oldProxy = 0.0;\n            for (int x : A) oldProxy += centroid_proxy_cost(x, ga, sumX, sumY, gsz);\n            for (int x : B) oldProxy += centroid_proxy_cost(x, gb, sumX, sumY, gsz);\n\n            double bestImp = 0.0;\n            vector<int> bestSelA, bestSelB;\n            double bestA = 0.0, bestB = 0.0;\n\n            int origMask = (1 << ka) - 1;\n\n            for (int mask = 0; mask < (1 << s); mask++) {\n                if (__builtin_popcount((unsigned)mask) != ka) continue;\n                if (mask == origMask) continue;\n\n                vector<int> selA, selB;\n                selA.reserve(ka);\n                selB.reserve(kb);\n\n                double newProxy = 0.0;\n                for (int i = 0; i < s; i++) {\n                    if (mask & (1 << i)) {\n                        selA.push_back(U[i]);\n                        newProxy += centroid_proxy_cost(U[i], ga, sumX, sumY, gsz);\n                    } else {\n                        selB.push_back(U[i]);\n                        newProxy += centroid_proxy_cost(U[i], gb, sumX, sumY, gsz);\n                    }\n                }\n\n                if (newProxy >= oldProxy * 0.997 && gsz[ga] + gsz[gb] > 24) continue;\n\n                vector<int> A2 = groups[ga];\n                vector<int> B2 = groups[gb];\n                for (int i = 0; i < ka; i++) A2[posA[i]] = selA[i];\n                for (int i = 0; i < kb; i++) B2[posB[i]] = selB[i];\n\n                double nA = complete_mst_cost(A2);\n                double nB = complete_mst_cost(B2);\n                double imp = oldPair - (nA + nB);\n                if (imp > bestImp + 1e-9) {\n                    bestImp = imp;\n                    bestSelA = selA;\n                    bestSelB = selB;\n                    bestA = nA;\n                    bestB = nB;\n                }\n            }\n\n            if (bestImp > 1e-9) {\n                vector<int> oldA = A, oldB = B;\n\n                for (int i = 0; i < ka; i++) {\n                    groups[ga][posA[i]] = bestSelA[i];\n                    cityGroup[bestSelA[i]] = ga;\n                    posInGroup[bestSelA[i]] = posA[i];\n                }\n                for (int i = 0; i < kb; i++) {\n                    groups[gb][posB[i]] = bestSelB[i];\n                    cityGroup[bestSelB[i]] = gb;\n                    posInGroup[bestSelB[i]] = posB[i];\n                }\n\n                long long oldSumAX = 0, oldSumAY = 0, newSumAX = 0, newSumAY = 0;\n                long long oldSumBX = 0, oldSumBY = 0, newSumBX = 0, newSumBY = 0;\n                for (int x : oldA) { oldSumAX += SX[x]; oldSumAY += SY[x]; }\n                for (int x : oldB) { oldSumBX += SX[x]; oldSumBY += SY[x]; }\n                for (int x : bestSelA) { newSumAX += SX[x]; newSumAY += SY[x]; }\n                for (int x : bestSelB) { newSumBX += SX[x]; newSumBY += SY[x]; }\n\n                sumX[ga] += newSumAX - oldSumAX;\n                sumY[ga] += newSumAY - oldSumAY;\n                sumX[gb] += newSumBX - oldSumBX;\n                sumY[gb] += newSumBY - oldSumBY;\n\n                gcost[ga] = bestA;\n                gcost[gb] = bestB;\n                any = true;\n            }\n        }\n        if (!any) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> Q >> L >> Wv;\n    G.resize(M);\n    for (int i = 0; i < M; i++) cin >> G[i];\n\n    for (int i = 0; i < N; i++) {\n        cin >> LX[i] >> RX[i] >> LY[i] >> RY[i];\n        SX[i] = LX[i] + RX[i];\n        SY[i] = LY[i] + RY[i];\n        WX[i] = RX[i] - LX[i];\n        WY[i] = RY[i] - LY[i];\n        MKEY[i] = mortonEncode((uint32_t)SX[i], (uint32_t)SY[i]);\n    }\n\n    vector<double> varTerm(N);\n    for (int i = 0; i < N; i++) {\n        varTerm[i] = (1.0 * WX[i] * WX[i] + 1.0 * WY[i] * WY[i]) / 12.0;\n    }\n    for (int i = 0; i < N; i++) {\n        estD[i][i] = 0.0;\n        for (int j = i + 1; j < N; j++) {\n            double dx = (SX[i] - SX[j]) * 0.5;\n            double dy = (SY[i] - SY[j]) * 0.5;\n            double d2 = dx * dx + dy * dy + varTerm[i] + varTerm[j];\n            estD[i][j] = estD[j][i] = sqrt(max(0.0, d2));\n        }\n    }\n\n    vector<int> allCities(N);\n    iota(allCities.begin(), allCities.end(), 0);\n\n    vector<int> cityMort = allCities, cityX = allCities, cityY = allCities, cityS = allCities, cityD = allCities;\n    sort(cityMort.begin(), cityMort.end(), cmpMortonCity);\n    sort(cityX.begin(), cityX.end(), cmpXCity);\n    sort(cityY.begin(), cityY.end(), cmpYCity);\n    sort(cityS.begin(), cityS.end(), cmpSumCity);\n    sort(cityD.begin(), cityD.end(), cmpDiffCity);\n\n    vector<int> cityMortRev = cityMort, cityXRev = cityX, cityYRev = cityY, citySRev = cityS, cityDRev = cityD;\n    reverse(cityMortRev.begin(), cityMortRev.end());\n    reverse(cityXRev.begin(), cityXRev.end());\n    reverse(cityYRev.begin(), cityYRev.end());\n    reverse(citySRev.begin(), citySRev.end());\n    reverse(cityDRev.begin(), cityDRev.end());\n\n    vector<int> groupAsc(M), groupDesc(M), groupOrig(M), groupRnd(M);\n    iota(groupAsc.begin(), groupAsc.end(), 0);\n    iota(groupDesc.begin(), groupDesc.end(), 0);\n    iota(groupOrig.begin(), groupOrig.end(), 0);\n    iota(groupRnd.begin(), groupRnd.end(), 0);\n\n    sort(groupAsc.begin(), groupAsc.end(), [&](int a, int b) {\n        if (G[a] != G[b]) return G[a] < G[b];\n        return a < b;\n    });\n    groupDesc = groupAsc;\n    reverse(groupDesc.begin(), groupDesc.end());\n\n    mt19937 rng(123456789);\n    shuffle(groupRnd.begin(), groupRnd.end(), rng);\n\n    double bestGroupingScore = INF;\n    vector<vector<int>> bestGroups;\n\n    auto try_grouping = [&](vector<vector<int>> cand) {\n        double sc = eval_grouping(cand);\n        if (sc < bestGroupingScore) {\n            bestGroupingScore = sc;\n            bestGroups = move(cand);\n        }\n    };\n\n    for (int mode = 0; mode < 3; mode++) {\n        try_grouping(makeKD(mode, groupAsc));\n        try_grouping(makeKD(mode, groupDesc));\n        try_grouping(makeKD(mode, groupOrig));\n        try_grouping(makeKD(mode, groupRnd));\n    }\n\n    try_grouping(makeContiguous(cityMort, groupAsc));\n    try_grouping(makeContiguous(cityMort, groupDesc));\n    try_grouping(makeContiguous(cityMort, groupOrig));\n    try_grouping(makeContiguous(cityMortRev, groupAsc));\n    try_grouping(makeContiguous(cityMortRev, groupDesc));\n\n    try_grouping(makeContiguous(cityX, groupAsc));\n    try_grouping(makeContiguous(cityX, groupDesc));\n    try_grouping(makeContiguous(cityX, groupOrig));\n    try_grouping(makeContiguous(cityXRev, groupAsc));\n    try_grouping(makeContiguous(cityXRev, groupDesc));\n\n    try_grouping(makeContiguous(cityY, groupAsc));\n    try_grouping(makeContiguous(cityY, groupDesc));\n    try_grouping(makeContiguous(cityY, groupOrig));\n    try_grouping(makeContiguous(cityYRev, groupAsc));\n    try_grouping(makeContiguous(cityYRev, groupDesc));\n\n    try_grouping(makeContiguous(cityS, groupAsc));\n    try_grouping(makeContiguous(cityS, groupDesc));\n    try_grouping(makeContiguous(cityS, groupOrig));\n    try_grouping(makeContiguous(citySRev, groupAsc));\n    try_grouping(makeContiguous(citySRev, groupDesc));\n\n    try_grouping(makeContiguous(cityD, groupAsc));\n    try_grouping(makeContiguous(cityD, groupDesc));\n    try_grouping(makeContiguous(cityD, groupOrig));\n    try_grouping(makeContiguous(cityDRev, groupAsc));\n    try_grouping(makeContiguous(cityDRev, groupDesc));\n\n    improve_grouping_swaps(bestGroups, cityMort, cityX, cityY, cityS, cityD);\n    improve_grouping_pairwise(bestGroups);\n    improve_grouping_subset_exchange(bestGroups);\n\n    vector<GroupOrderPack> orderPacks(M);\n    vector<double> groupEstCost(M, 0.0);\n    vector<vector<pair<int,int>>> estMSTEdges(M);\n    vector<vector<int>> outputCityOrder(M);\n    vector<int> baseNeed(M, 0);\n\n    for (int gid = 0; gid < M; gid++) {\n        groupEstCost[gid] = complete_mst_cost(bestGroups[gid]);\n        auto mstInfo = complete_mst_edges(bestGroups[gid]);\n        estMSTEdges[gid] = mstInfo.second;\n\n        orderPacks[gid] = make_group_orders(bestGroups[gid], estMSTEdges[gid]);\n        if (!orderPacks[gid].ranked.empty()) outputCityOrder[gid] = orderPacks[gid].ranked[0];\n        else outputCityOrder[gid] = bestGroups[gid];\n\n        baseNeed[gid] = (int)gen_dp_cover_windows(outputCityOrder[gid]).size();\n        if (G[gid] == 2) baseNeed[gid] = 0;\n        if (3 <= G[gid] && G[gid] <= L) baseNeed[gid] = 1;\n    }\n\n    vector<int> priorityGroups(M);\n    iota(priorityGroups.begin(), priorityGroups.end(), 0);\n    sort(priorityGroups.begin(), priorityGroups.end(), [&](int a, int b) {\n        double va = groupEstCost[a] / max(1, baseNeed[a]);\n        double vb = groupEstCost[b] / max(1, baseNeed[b]);\n        if (fabs(va - vb) > 1e-12) return va > vb;\n        if (fabs(groupEstCost[a] - groupEstCost[b]) > 1e-12) return groupEstCost[a] > groupEstCost[b];\n        return G[a] > G[b];\n    });\n\n    vector<unordered_map<long long,int>> queryEdgeCount(M);\n    vector<vector<pair<int,int>>> exactSmallGroupEdges(M);\n    vector<vector<pair<int,int>>> baseExactTree(M);\n    vector<set<vector<int>>> seenSubsets(M);\n\n    auto norm_edge = [&](int a, int b) {\n        if (a > b) swap(a, b);\n        return pair<int,int>(a, b);\n    };\n\n    int usedQueries = 0;\n\n    // Base mandatory cover:\n    // Build the exact cover tree explicitly using queried MSTs for size>=3 blocks\n    // and direct edges for size-2 blocks.\n    for (int gid = 0; gid < M; gid++) {\n        int g = G[gid];\n        if (g <= 1) continue;\n        if (g == 2) {\n            auto e = norm_edge(outputCityOrder[gid][0], outputCityOrder[gid][1]);\n            baseExactTree[gid].push_back(e);\n            queryEdgeCount[gid][edgeKey(e.first, e.second)]++;\n            continue;\n        }\n\n        auto blocks = gen_dp_cover_blocks_all(outputCityOrder[gid]);\n        for (auto& sub : blocks) {\n            if ((int)sub.size() == 2) {\n                auto e = norm_edge(sub[0], sub[1]);\n                baseExactTree[gid].push_back(e);\n                queryEdgeCount[gid][edgeKey(e.first, e.second)]++;\n            } else {\n                vector<int> key = sub;\n                sort(key.begin(), key.end());\n                seenSubsets[gid].insert(key);\n\n                auto ret = ask(sub);\n                usedQueries++;\n                for (auto [a, b] : ret) {\n                    baseExactTree[gid].push_back({a, b});\n                    queryEdgeCount[gid][edgeKey(a, b)]++;\n                }\n                if ((int)sub.size() == G[gid]) {\n                    exactSmallGroupEdges[gid] = ret;\n                }\n            }\n        }\n    }\n\n    vector<QueryPlan> plans;\n    plans.reserve(Q);\n\n    auto try_add_plan = [&](int gid, const vector<int>& sub) {\n        if (usedQueries + (int)plans.size() >= Q) return;\n        if ((int)sub.size() < 3 || (int)sub.size() > L) return;\n        vector<int> key = sub;\n        sort(key.begin(), key.end());\n        if (seenSubsets[gid].insert(key).second) {\n            plans.push_back({gid, sub});\n        }\n    };\n\n    int midOffset = (L - 1) / 2;\n\n    auto add_round = [&](int ordIdx, int offset, bool coverStyle) {\n        vector<vector<vector<int>>> wins(M);\n        int mx = 0;\n        for (int gid : priorityGroups) {\n            if (usedQueries + (int)plans.size() >= Q) return;\n            if (G[gid] <= L) continue;\n            if ((int)orderPacks[gid].ranked.size() <= ordIdx) continue;\n            const auto& ord = orderPacks[gid].ranked[ordIdx];\n            if (coverStyle) wins[gid] = gen_dp_cover_windows(ord);\n            else wins[gid] = gen_regular_windows(ord, offset);\n            mx = max(mx, (int)wins[gid].size());\n        }\n        for (int t = 0; t < mx; t++) {\n            for (int gid : priorityGroups) {\n                if (usedQueries + (int)plans.size() >= Q) return;\n                if (t < (int)wins[gid].size()) try_add_plan(gid, wins[gid][t]);\n            }\n        }\n    };\n\n    add_round(1, 0, true);\n    if (midOffset > 0) add_round(0, midOffset, false);\n    if (midOffset > 0) add_round(1, midOffset, false);\n    add_round(2, 0, true);\n    if (midOffset != 1 && L >= 4) add_round(0, 1, false);\n\n    for (auto& qp : plans) {\n        auto ret = ask(qp.subset);\n        for (auto [a, b] : ret) {\n            queryEdgeCount[qp.gid][edgeKey(a, b)]++;\n        }\n    }\n\n    for (int gid = 0; gid < M; gid++) {\n        for (auto& e : baseExactTree[gid]) {\n            if (e.first > e.second) swap(e.first, e.second);\n        }\n        sort(baseExactTree[gid].begin(), baseExactTree[gid].end());\n    }\n\n    vector<vector<pair<int,int>>> answerEdges(M);\n\n    for (int gid = 0; gid < M; gid++) {\n        int g = G[gid];\n        const auto& group = bestGroups[gid];\n        answerEdges[gid].clear();\n\n        if (g <= 1) continue;\n\n        if (g == 2) {\n            int a = group[0], b = group[1];\n            if (a > b) swap(a, b);\n            answerEdges[gid].push_back({a, b});\n            continue;\n        }\n\n        if (g <= L && !exactSmallGroupEdges[gid].empty()) {\n            answerEdges[gid] = exactSmallGroupEdges[gid];\n            sort(answerEdges[gid].begin(), answerEdges[gid].end());\n            continue;\n        }\n\n        auto& qcnt = queryEdgeCount[gid];\n        unordered_set<long long> edgeSeen;\n\n        struct EItem {\n            double w;\n            int u, v;\n        };\n        vector<EItem> cand;\n        cand.reserve(g * 36);\n\n        auto addCand = [&](int u, int v) {\n            if (u == v) return;\n            if (u > v) swap(u, v);\n            long long key = edgeKey(u, v);\n            if (!edgeSeen.insert(key).second) return;\n            int cnt = 0;\n            auto it = qcnt.find(key);\n            if (it != qcnt.end()) cnt = it->second;\n            double factor = 1.0 / (1.0 + 0.18 * min(cnt, 4));\n            cand.push_back({estD[u][v] * factor, u, v});\n        };\n\n        for (auto& kv : qcnt) {\n            int u = (int)(kv.first >> 11);\n            int v = (int)(kv.first & ((1 << 11) - 1));\n            addCand(u, v);\n        }\n\n        for (auto [a, b] : estMSTEdges[gid]) addCand(a, b);\n\n        vector<vector<int>> useOrders;\n        for (int t = 0; t < min(6, (int)orderPacks[gid].ranked.size()); t++) {\n            useOrders.push_back(orderPacks[gid].ranked[t]);\n        }\n        auto ensure_order = [&](const vector<int>& ord) {\n            for (auto& v : useOrders) if (v == ord) return;\n            useOrders.push_back(ord);\n        };\n        ensure_order(sort_morton(group));\n        ensure_order(sort_x(group));\n        ensure_order(sort_y(group));\n        ensure_order(sort_sum(group));\n        ensure_order(sort_diff(group));\n\n        for (int oi = 0; oi < (int)useOrders.size(); oi++) {\n            auto& ord = useOrders[oi];\n            int gg = (int)ord.size();\n            int maxJump = (oi < 4 ? 3 : 2);\n            for (int i = 0; i < gg; i++) {\n                for (int d = 1; d <= maxJump; d++) {\n                    if (i + d < gg) addCand(ord[i], ord[i + d]);\n                }\n            }\n        }\n\n        const int KNN = 6;\n        for (int i = 0; i < g; i++) {\n            int u = group[i];\n            vector<pair<double,int>> tmp;\n            tmp.reserve(g - 1);\n            for (int j = 0; j < g; j++) {\n                if (i == j) continue;\n                int v = group[j];\n                tmp.push_back({estD[u][v], v});\n            }\n            int lim = min(KNN, (int)tmp.size());\n            if ((int)tmp.size() > lim) nth_element(tmp.begin(), tmp.begin() + lim, tmp.end());\n            for (int t = 0; t < lim; t++) addCand(u, tmp[t].second);\n        }\n\n        sort(cand.begin(), cand.end(), [&](const EItem& a, const EItem& b) {\n            if (fabs(a.w - b.w) > 1e-12) return a.w < b.w;\n            if (a.u != b.u) return a.u < b.u;\n            return a.v < b.v;\n        });\n\n        DSU dsu(N);\n        vector<pair<int,int>> chosen;\n        chosen.reserve(g - 1);\n\n        for (auto& e : cand) {\n            if (dsu.unite(e.u, e.v)) {\n                chosen.push_back({e.u, e.v});\n                if ((int)chosen.size() == g - 1) break;\n            }\n        }\n\n        if ((int)chosen.size() < g - 1) {\n            auto ord = outputCityOrder[gid];\n            for (int i = 1; i < (int)ord.size(); i++) {\n                int a = ord[i - 1], b = ord[i];\n                if (a > b) swap(a, b);\n                if (dsu.unite(a, b)) chosen.push_back({a, b});\n            }\n        }\n\n        for (auto& e : chosen) {\n            if (e.first > e.second) swap(e.first, e.second);\n        }\n        sort(chosen.begin(), chosen.end());\n\n        auto treeScore = [&](const vector<pair<int,int>>& edges) -> double {\n            double s = 0.0;\n            for (auto [a, b] : edges) {\n                int cnt = 0;\n                auto it = qcnt.find(edgeKey(a, b));\n                if (it != qcnt.end()) cnt = it->second;\n                double factor = 1.0 / (1.0 + 0.20 * min(cnt, 4));\n                s += estD[a][b] * factor;\n            }\n            return s;\n        };\n\n        // Compare against exact base cover tree and slightly bias toward it\n        // because it is composed of exact local MST edges / exact size-2 edges.\n        if ((int)baseExactTree[gid].size() == g - 1) {\n            double sparseScore = treeScore(chosen);\n            double baseScore = treeScore(baseExactTree[gid]);\n            if (baseScore <= sparseScore * 1.003) {\n                chosen = baseExactTree[gid];\n            }\n        }\n\n        answerEdges[gid] = move(chosen);\n    }\n\n    cout << \"!\" << '\\n';\n    for (int gid = 0; gid < M; gid++) {\n        const auto& ord = outputCityOrder[gid];\n        for (int i = 0; i < (int)ord.size(); i++) {\n            if (i) cout << ' ';\n            cout << ord[i];\n        }\n        cout << '\\n';\n        for (auto [a, b] : answerEdges[gid]) {\n            cout << a << ' ' << b << '\\n';\n        }\n    }\n    cout.flush();\n\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int MAXN = 20;\nstatic constexpr int MAXM = 40;\nstatic constexpr int MAXV = 400;\nstatic constexpr int INF = 1e9;\n\nstruct Point {\n    int r, c;\n};\n\nstruct Cmd {\n    char a, d;\n};\n\nstruct Graph {\n    array<uint8_t, MAXV> cnt{};\n    array<array<uint16_t, 8>, MAXV> to{};\n    array<array<uint8_t, 8>, MAXV> act{};\n\n    array<uint8_t, MAXV> rcnt{};\n    array<array<uint16_t, 128>, MAXV> rev{};\n};\n\nstruct Solver {\n    int N, M, V;\n    array<Point, MAXM> pts{};\n    array<int, MAXM> cells{};\n    array<int, MAXV> rankCell{}; // -1 if not target, else target index\n\n    vector<int> cand[MAXM]; // candidate stopper cell ids for each target, includes -1\n\n    mt19937 rng{123456789};\n    chrono::steady_clock::time_point st;\n    double TL = 1.78;\n\n    const int dr[4] = {-1, 1, 0, 0};\n    const int dc[4] = {0, 0, -1, 1};\n    const char dirC[4] = {'U', 'D', 'L', 'R'};\n\n    Graph g0, g1;\n    array<short, MAXV> dist0{}, dist1{}, dist2{};\n    array<short, MAXV> prevPos{};\n    array<int8_t, MAXV> prevAct{};\n\n    using Assign = array<int, MAXM>;\n\n    Solver(int N_, int M_, const vector<Point>& in) : N(N_), M(M_), V(N_ * N_) {\n        rankCell.fill(-1);\n        for (int i = 0; i < M; i++) {\n            pts[i] = in[i];\n            cells[i] = id(pts[i].r, pts[i].c);\n            rankCell[cells[i]] = i;\n        }\n        build_candidates();\n        st = chrono::steady_clock::now();\n    }\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - st).count();\n    }\n    inline bool time_up(double margin = 0.0) const {\n        return elapsed() >= TL - margin;\n    }\n\n    inline int id(int r, int c) const { return r * N + c; }\n    inline int row(int v) const { return v / N; }\n    inline int col(int v) const { return v % N; }\n    inline bool inside(int r, int c) const { return 0 <= r && r < N && 0 <= c && c < N; }\n\n    int adj_dir(int from, int to) const {\n        int fr = row(from), fc = col(from);\n        int tr = row(to), tc = col(to);\n        for (int d = 0; d < 4; d++) {\n            if (fr + dr[d] == tr && fc + dc[d] == tc) return d;\n        }\n        return -1;\n    }\n\n    void build_candidates() {\n        for (int k = 1; k < M; k++) {\n            cand[k].clear();\n            cand[k].push_back(-1);\n\n            int r = pts[k].r, c = pts[k].c;\n            vector<int> tmp;\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                int v = id(nr, nc);\n                // Allow non-target or already visited target as blocker cell.\n                if (rankCell[v] == -1 || rankCell[v] < k) tmp.push_back(v);\n            }\n            sort(tmp.begin(), tmp.end());\n            tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());\n            for (int v : tmp) cand[k].push_back(v);\n        }\n    }\n\n    void build_graph(const array<uint8_t, MAXV>& blocked, Graph& g) const {\n        int slU[MAXV], slD[MAXV], slL[MAXV], slR[MAXV];\n        g.cnt.fill(0);\n        g.rcnt.fill(0);\n\n        for (int r = 0; r < N; r++) {\n            int lb = -1;\n            for (int c = 0; c < N; c++) {\n                int v = id(r, c);\n                if (blocked[v]) lb = c;\n                else slL[v] = id(r, lb + 1);\n            }\n            int rb = N;\n            for (int c = N - 1; c >= 0; c--) {\n                int v = id(r, c);\n                if (blocked[v]) rb = c;\n                else slR[v] = id(r, rb - 1);\n            }\n        }\n\n        for (int c = 0; c < N; c++) {\n            int ub = -1;\n            for (int r = 0; r < N; r++) {\n                int v = id(r, c);\n                if (blocked[v]) ub = r;\n                else slU[v] = id(ub + 1, c);\n            }\n            int db = N;\n            for (int r = N - 1; r >= 0; r--) {\n                int v = id(r, c);\n                if (blocked[v]) db = r;\n                else slD[v] = id(db - 1, c);\n            }\n        }\n\n        for (int p = 0; p < V; p++) {\n            if (blocked[p]) continue;\n            int r = row(p), c = col(p);\n\n            auto add_edge = [&](int to, int act) {\n                if (to == p) return;\n                auto &cc = g.cnt[p];\n                for (int i = 0; i < cc; i++) {\n                    if (g.to[p][i] == to) return;\n                }\n                g.to[p][cc] = (uint16_t)to;\n                g.act[p][cc] = (uint8_t)act;\n                cc++;\n            };\n\n            add_edge(slU[p], 4);\n            add_edge(slD[p], 5);\n            add_edge(slL[p], 6);\n            add_edge(slR[p], 7);\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                int v = id(nr, nc);\n                if (!blocked[v]) add_edge(v, d);\n            }\n        }\n\n        for (int u = 0; u < V; u++) {\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                g.rev[v][g.rcnt[v]++] = (uint16_t)u;\n            }\n        }\n    }\n\n    void bfs_all(const Graph& g, int src, int forbid, array<short, MAXV>& dist) const {\n        dist.fill(-1);\n        if (src == forbid) return;\n\n        static int q[MAXV];\n        int qh = 0, qt = 0;\n        dist[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    void bfs_rev_all(const Graph& g, int dst, int forbid, array<short, MAXV>& dist) const {\n        dist.fill(-1);\n        if (dst == forbid) return;\n\n        static int q[MAXV];\n        int qh = 0, qt = 0;\n        dist[dst] = 0;\n        q[qt++] = dst;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist[u] + 1;\n            for (int i = 0; i < g.rcnt[u]; i++) {\n                int v = g.rev[u][i];\n                if (v == forbid || dist[v] != -1) continue;\n                dist[v] = nd;\n                q[qt++] = v;\n            }\n        }\n    }\n\n    bool bfs_path(const Graph& g, int src, int dst, int forbid, vector<int>& acts) {\n        acts.clear();\n        if (src == dst) return true;\n\n        dist0.fill(-1);\n        prevPos.fill(-1);\n        prevAct.fill(-1);\n\n        if (src == forbid) return false;\n\n        static int q[MAXV];\n        int qh = 0, qt = 0;\n        dist0[src] = 0;\n        q[qt++] = src;\n\n        while (qh < qt) {\n            int u = q[qh++];\n            short nd = dist0[u] + 1;\n            for (int i = 0; i < g.cnt[u]; i++) {\n                int v = g.to[u][i];\n                if (v == forbid || dist0[v] != -1) continue;\n                dist0[v] = nd;\n                prevPos[v] = (short)u;\n                prevAct[v] = (int8_t)g.act[u][i];\n                if (v == dst) {\n                    qh = qt;\n                    break;\n                }\n                q[qt++] = v;\n            }\n        }\n\n        if (dist0[dst] == -1) return false;\n\n        int cur = dst;\n        while (cur != src) {\n            acts.push_back(prevAct[cur]);\n            cur = prevPos[cur];\n        }\n        reverse(acts.begin(), acts.end());\n        return true;\n    }\n\n    void append_acts(vector<Cmd>& ans, const vector<int>& acts) const {\n        for (int a : acts) {\n            if (a < 4) ans.push_back({'M', dirC[a]});\n            else ans.push_back({'S', dirC[a - 4]});\n        }\n    }\n\n    Cmd alter_cmd(int from, int block_cell) const {\n        int d = adj_dir(from, block_cell);\n        return {'A', dirC[d]};\n    }\n\n    // Exact evaluation with lazy placement.\n    int eval_assignment(const Assign& asg, int cutoff = INF) {\n        array<uint8_t, MAXV> blocked{}, used{};\n        blocked.fill(0);\n        used.fill(0);\n\n        int total = 0;\n        for (int k = 1; k < M; k++) {\n            int x = asg[k];\n            if (x != -1 && !used[x]) {\n                used[x] = 1;\n                total++;\n            }\n        }\n        if (total >= cutoff) return total;\n\n        bool haveG = false;\n        int cur = cells[0];\n\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            if (!haveG) {\n                build_graph(blocked, g0);\n                haveG = true;\n            }\n\n            bfs_all(g0, cur, -1, dist0);\n            int best = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            bool add_new = (x != -1 && !blocked[x]);\n            if (add_new) {\n                bfs_all(g0, cur, target, dist1);\n\n                blocked[x] = 1;\n                build_graph(blocked, g1);\n                bfs_rev_all(g1, target, -1, dist2);\n                blocked[x] = 0;\n\n                int xr = row(x), xc = col(x);\n                int pre = INF;\n                for (int d = 0; d < 4; d++) {\n                    int vr = xr + dr[d], vc = xc + dc[d];\n                    if (!inside(vr, vc)) continue;\n                    int v = id(vr, vc);\n                    if (v == target) continue;\n                    if (blocked[v]) continue;\n                    if (dist1[v] == -1 || dist2[v] == -1) continue;\n                    pre = min(pre, (int)dist1[v] + (int)dist2[v]);\n                }\n                best = min(best, pre);\n            }\n\n            if (best >= INF) return INF;\n            total += best;\n            if (total >= cutoff) return total;\n\n            if (add_new) {\n                blocked[x] = 1;\n                g0 = g1;      // reuse next graph\n                haveG = true;\n            }\n            cur = target;\n        }\n        return total;\n    }\n\n    Assign none_assign() const {\n        Assign a;\n        a.fill(-1);\n        return a;\n    }\n\n    Assign heuristic_prev_assign() const {\n        Assign asg;\n        asg.fill(-1);\n\n        for (int k = 1; k < M; k++) {\n            int cur = cells[k], prv = cells[k - 1];\n            int r = row(cur), c = col(cur);\n            int pr = row(prv), pc = col(prv);\n\n            vector<int> pref;\n            if (abs(pc - c) <= abs(pr - r)) {\n                if (pr <= r) pref = {1, 0, 3, 2};\n                else         pref = {0, 1, 2, 3};\n            } else {\n                if (pc <= c) pref = {3, 2, 1, 0};\n                else         pref = {2, 3, 0, 1};\n            }\n\n            int chosen = -1;\n            for (int pd : pref) {\n                for (int x : cand[k]) {\n                    if (x == -1) continue;\n                    if (adj_dir(cur, x) == pd) {\n                        chosen = x;\n                        break;\n                    }\n                }\n                if (chosen != -1) break;\n            }\n            asg[k] = chosen;\n        }\n        return asg;\n    }\n\n    // Greedy completion from a fixed prefix [1, start_k-1].\n    // If lookahead=true, prefer choices that also help the next segment.\n    Assign greedy_from_prefix(const Assign& base, int start_k, bool lookahead) {\n        Assign asg = base;\n\n        array<uint8_t, MAXV> used{}, blocked{};\n        used.fill(0);\n        blocked.fill(0);\n\n        for (int k = 1; k < start_k; k++) {\n            int x = asg[k];\n            if (x != -1) {\n                used[x] = 1;\n                blocked[x] = 1;\n            }\n        }\n\n        int cur = cells[start_k - 1];\n        bool haveG = false;\n\n        for (int k = start_k; k < M; k++) {\n            int target = cells[k];\n            int nxt = (k + 1 < M ? cells[k + 1] : -1);\n\n            if (!haveG) {\n                build_graph(blocked, g0);\n                haveG = true;\n            }\n\n            bfs_all(g0, cur, -1, dist0);\n            int direct = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            bool anyNew = false;\n            for (int x : cand[k]) {\n                if (x != -1 && !blocked[x]) {\n                    anyNew = true;\n                    break;\n                }\n            }\n            if (anyNew) bfs_all(g0, cur, target, dist1);\n\n            int bestx = -1;\n            int bestHeu = INF;\n            int bestBase = INF;\n\n            for (int x : cand[k]) {\n                int mv = direct;\n                int nextDist = 0;\n                bool add_new = (x != -1 && !blocked[x]);\n                const Graph* afterG = &g0;\n\n                if (add_new) {\n                    blocked[x] = 1;\n                    build_graph(blocked, g1);\n                    blocked[x] = 0;\n                    afterG = &g1;\n\n                    bfs_rev_all(g1, target, -1, dist2);\n                    int xr = row(x), xc = col(x);\n                    int pre = INF;\n                    for (int d = 0; d < 4; d++) {\n                        int vr = xr + dr[d], vc = xc + dc[d];\n                        if (!inside(vr, vc)) continue;\n                        int v = id(vr, vc);\n                        if (v == target) continue;\n                        if (blocked[v]) continue;\n                        if (dist1[v] == -1 || dist2[v] == -1) continue;\n                        pre = min(pre, (int)dist1[v] + (int)dist2[v]);\n                    }\n                    mv = min(mv, pre);\n                }\n\n                if (mv >= INF) continue;\n                int extra = (x != -1 && !used[x]) ? 1 : 0;\n                int baseScore = mv + extra;\n\n                if (lookahead && nxt != -1) {\n                    bfs_all(*afterG, target, -1, dist2);\n                    nextDist = (dist2[nxt] == -1 ? 1000 : (int)dist2[nxt]);\n                }\n\n                int heu = lookahead ? (3 * baseScore + nextDist) : baseScore;\n\n                if (heu < bestHeu ||\n                    (heu == bestHeu && baseScore < bestBase) ||\n                    (heu == bestHeu && baseScore == bestBase && x < bestx)) {\n                    bestHeu = heu;\n                    bestBase = baseScore;\n                    bestx = x;\n                }\n            }\n\n            asg[k] = bestx;\n            if (bestx != -1) used[bestx] = 1;\n            if (bestx != -1 && !blocked[bestx]) {\n                blocked[bestx] = 1;\n                haveG = false;\n            }\n            cur = target;\n        }\n\n        return asg;\n    }\n\n    Assign greedy_init_assign(bool lookahead) {\n        Assign base = none_assign();\n        return greedy_from_prefix(base, 1, lookahead);\n    }\n\n    Assign random_assign() {\n        Assign asg;\n        asg.fill(-1);\n        for (int k = 1; k < M; k++) {\n            int idx = (int)(rng() % cand[k].size());\n            asg[k] = cand[k][idx];\n        }\n        return asg;\n    }\n\n    pair<Assign, int> improve_assignment(Assign asg, int curScore, int passes) {\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 1);\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (time_up(0.10)) break;\n            shuffle(order.begin(), order.end(), rng);\n            bool improved = false;\n\n            for (int k : order) {\n                if (time_up(0.08)) break;\n\n                int old = asg[k];\n                int bestx = old;\n                int bestScore = curScore;\n\n                for (int x : cand[k]) {\n                    if (x == old) continue;\n                    asg[k] = x;\n                    int sc = eval_assignment(asg, bestScore);\n                    if (sc < bestScore) {\n                        bestScore = sc;\n                        bestx = x;\n                    }\n                }\n\n                asg[k] = bestx;\n                if (bestx != old) {\n                    curScore = bestScore;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {asg, curScore};\n    }\n\n    vector<Cmd> build_answer_assignment(const Assign& asg) {\n        vector<Cmd> ans;\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        vector<int> acts;\n        int cur = cells[0];\n        bool haveG = false;\n\n        for (int k = 1; k < M; k++) {\n            int target = cells[k];\n            int x = asg[k];\n\n            if (!haveG) {\n                build_graph(blocked, g0);\n                haveG = true;\n            }\n\n            bfs_all(g0, cur, -1, dist0);\n            int direct = (dist0[target] == -1 ? INF : (int)dist0[target]);\n\n            int pre = INF, bestV = -1;\n            bool add_new = (x != -1 && !blocked[x]);\n\n            if (add_new) {\n                bfs_all(g0, cur, target, dist1);\n\n                blocked[x] = 1;\n                build_graph(blocked, g1);\n                bfs_rev_all(g1, target, -1, dist2);\n                blocked[x] = 0;\n\n                int xr = row(x), xc = col(x);\n                for (int d = 0; d < 4; d++) {\n                    int vr = xr + dr[d], vc = xc + dc[d];\n                    if (!inside(vr, vc)) continue;\n                    int v = id(vr, vc);\n                    if (v == target) continue;\n                    if (blocked[v]) continue;\n                    if (dist1[v] == -1 || dist2[v] == -1) continue;\n                    int sc = (int)dist1[v] + (int)dist2[v];\n                    if (sc < pre) {\n                        pre = sc;\n                        bestV = v;\n                    }\n                }\n            }\n\n            bool use_pre = (pre < direct);\n\n            if (!use_pre) {\n                if (!bfs_path(g0, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n\n                if (add_new) {\n                    ans.push_back(alter_cmd(cur, x));\n                    blocked[x] = 1;\n                    g0 = g1;   // reuse graph of the new board\n                    haveG = true;\n                }\n            } else {\n                if (!bfs_path(g0, cur, bestV, target, acts)) return {};\n                append_acts(ans, acts);\n                cur = bestV;\n\n                ans.push_back(alter_cmd(cur, x));\n                blocked[x] = 1;\n\n                build_graph(blocked, g1);\n                if (!bfs_path(g1, cur, target, -1, acts)) return {};\n                append_acts(ans, acts);\n                cur = target;\n\n                g0 = g1;\n                haveG = true;\n            }\n        }\n\n        return ans;\n    }\n\n    pair<bool, int> simulate(const vector<Cmd>& ans) const {\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n\n        int cur = cells[0];\n        int t = 1;\n\n        auto dir_idx = [&](char d) -> int {\n            if (d == 'U') return 0;\n            if (d == 'D') return 1;\n            if (d == 'L') return 2;\n            return 3;\n        };\n\n        for (const auto& cmd : ans) {\n            int d = dir_idx(cmd.d);\n            if (cmd.a == 'M') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                if (blocked[v]) return {false, (int)ans.size()};\n                cur = v;\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'S') {\n                int rr = row(cur), cc = col(cur);\n                while (true) {\n                    int nr = rr + dr[d], nc = cc + dc[d];\n                    if (!inside(nr, nc)) break;\n                    int v = id(nr, nc);\n                    if (blocked[v]) break;\n                    rr = nr;\n                    cc = nc;\n                }\n                cur = id(rr, cc);\n                if (t < M && cur == cells[t]) t++;\n            } else if (cmd.a == 'A') {\n                int nr = row(cur) + dr[d], nc = col(cur) + dc[d];\n                if (!inside(nr, nc)) return {false, (int)ans.size()};\n                int v = id(nr, nc);\n                blocked[v] ^= 1;\n            } else {\n                return {false, (int)ans.size()};\n            }\n        }\n\n        bool ok = (t == M && (int)ans.size() <= 2 * N * M);\n        return {ok, (int)ans.size()};\n    }\n\n    vector<Cmd> build_empty_fallback() {\n        vector<Cmd> ans;\n        array<uint8_t, MAXV> blocked{};\n        blocked.fill(0);\n        build_graph(blocked, g0);\n\n        vector<int> acts;\n        int cur = cells[0];\n        for (int k = 1; k < M; k++) {\n            if (bfs_path(g0, cur, cells[k], -1, acts)) {\n                append_acts(ans, acts);\n            } else {\n                int cr = row(cur), cc = col(cur);\n                int tr = row(cells[k]), tc = col(cells[k]);\n                while (cr < tr) ans.push_back({'M', 'D'}), cr++;\n                while (cr > tr) ans.push_back({'M', 'U'}), cr--;\n                while (cc < tc) ans.push_back({'M', 'R'}), cc++;\n                while (cc > tc) ans.push_back({'M', 'L'}), cc--;\n            }\n            cur = cells[k];\n        }\n        return ans;\n    }\n\n    vector<Cmd> solve() {\n        Assign bestAsg = none_assign();\n        int bestScore = eval_assignment(bestAsg);\n\n        vector<Assign> seeds;\n        seeds.push_back(bestAsg);\n        seeds.push_back(heuristic_prev_assign());\n        seeds.push_back(greedy_init_assign(false));\n        if (!time_up(0.45)) seeds.push_back(greedy_init_assign(true));\n\n        for (auto seed : seeds) {\n            if (time_up(0.30)) break;\n            int sc = eval_assignment(seed);\n            auto res = improve_assignment(seed, sc, 2);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n        }\n\n        int iter = 0;\n        int suffix_trials = 0;\n\n        while (!time_up(0.18)) {\n            Assign cur = bestAsg;\n            int mode = iter % 6;\n\n            if (mode <= 2) {\n                int changes = 1 + (rng() % 3);\n                for (int t = 0; t < changes; t++) {\n                    int k = 1 + (int)(rng() % (M - 1));\n                    int idx = (int)(rng() % cand[k].size());\n                    cur[k] = cand[k][idx];\n                }\n                if (mode == 2 && M >= 3) {\n                    int k = 1 + (int)(rng() % (M - 2));\n                    int i1 = (int)(rng() % cand[k].size());\n                    int i2 = (int)(rng() % cand[k + 1].size());\n                    cur[k] = cand[k][i1];\n                    cur[k + 1] = cand[k + 1][i2];\n                }\n            } else if (suffix_trials < 8) {\n                int start_k = 1 + (int)(rng() % (M - 1));\n                bool lookahead = (mode == 3 || mode == 5);\n                cur = greedy_from_prefix(bestAsg, start_k, lookahead);\n                suffix_trials++;\n            } else {\n                cur = random_assign();\n            }\n\n            int sc = eval_assignment(cur, bestScore + 28);\n            if (sc < bestScore + 28) {\n                int passes = (mode >= 3 && mode <= 5) ? 2 : 1;\n                auto res = improve_assignment(cur, sc, passes);\n                if (res.second < bestScore) {\n                    bestScore = res.second;\n                    bestAsg = res.first;\n                }\n            }\n            iter++;\n        }\n\n        if (!time_up(0.08)) {\n            auto res = improve_assignment(bestAsg, bestScore, 1);\n            if (res.second < bestScore) {\n                bestScore = res.second;\n                bestAsg = res.first;\n            }\n        }\n\n        vector<Cmd> ans = build_answer_assignment(bestAsg);\n        auto [ok, len] = simulate(ans);\n\n        if (!ok) {\n            Assign none = none_assign();\n            ans = build_answer_assignment(none);\n            auto [ok2, len2] = simulate(ans);\n            if (!ok2) {\n                ans.clear();\n                int cur = cells[0];\n                for (int i = 1; i < M; i++) {\n                    int tr = row(cells[i]), tc = col(cells[i]);\n                    int cr = row(cur), cc = col(cur);\n                    while (cr < tr) ans.push_back({'M', 'D'}), cr++;\n                    while (cr > tr) ans.push_back({'M', 'U'}), cr--;\n                    while (cc < tc) ans.push_back({'M', 'R'}), cc++;\n                    while (cc > tc) ans.push_back({'M', 'L'}), cc--;\n                    cur = cells[i];\n                }\n            }\n        }\n\n        return ans;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M;\n    cin >> N >> M;\n    vector<Point> pts(M);\n    for (int i = 0; i < M; i++) cin >> pts[i].r >> pts[i].c;\n\n    Solver solver(N, M, pts);\n    vector<Cmd> ans = solver.solve();\n\n    for (auto &c : ans) {\n        cout << c.a << ' ' << c.d << '\\n';\n    }\n    return 0;\n}"}}}